设计模式之建造者模式

Posted 蔡鸿军

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之建造者模式相关的知识,希望对你有一定的参考价值。

      今天这篇博客将要讲到设计模式,可能在我们日常的项目里面会有很多的运用场景。但是有的时候如果我们不知道运用该设计模式时,将会写出那种烂而肥的代码,甚至有的时候完全没有高级语言该有的那种优雅性、可维护性。

      下面跟大家分享一个笔者前段时间在项目里面遇到的一个问题场景:售货机大家都应该听说过,在售货机上面都有一个可以收取硬币或者纸币的货币器(后面笔者为了代码陈述方便,会将货币器拆分为硬币器和纸币器),别看我们在购买一瓶饮料的时候,只需要简简单单的投入3-5块钱就可以了。其实在硬件层面它还是需要做很多的事情,首先打开串口(open),其次发送重置指令(reset),再其次发送使能指令(enable),有的货币器可能还需要发送查询指令(select),在整个过程中我们还需要开启一个轮训线程监听用户的投币状态(startThread)。就上面这些流程,如果我们使用那种线条型的代码去做的话,我们将会看到代码非常不易维护。假如现在我们来从建造者模式的角度重新规划整个代码结构的话,我们应该怎么写呢?

      首先肯定需要定义一个抽象的模型方法CurrentPartModel,在这个类里面定义好所需要的协议方法,代码如下:

public abstract class CurrentPartModel {

	private ArrayList<String> sequence=new ArrayList<String>();
	protected abstract void open();
	protected abstract void reset();
	protected abstract void enable();
	protected abstract void select();
	protected abstract void startThread();
	
	final public void run(){
		for(int i=0;i<sequence.size();i++){
			if(sequence.get(i).equals("open")){
				this.open();
			}else if(sequence.get(i).equals("reset")){
				this.reset();
			}else if(sequence.get(i).equals("enable")){
				this.enable();
			}else if(sequence.get(i).equals("select")){
				this.select();
			}else if(sequence.get(i).equals("startThread")){
				this.startThread();
			}
		}
	}
	
	final public void setSequence(ArrayList<String> sequence){
		this.sequence=sequence;
	}
}

      然后在这个模型基础上,扩展出两个新的模型分别表示:硬币器和纸币器。请看如下代码:

public class CoinModel extends CurrentPartModel {

	@Override
	protected void open() {
		System.out.println("打开硬币器");
	}

	@Override
	protected void reset() {
		System.out.println("重置硬币器");
	}

	@Override
	protected void enable() {
		System.out.println("使能硬币器");
	}

	@Override
	protected void select() {
		System.out.println("查询硬币器");
	}

	@Override
	protected void startThread() {
		System.out.println("开启硬币轮训线程");
	}
}
public class BillModel extends CurrentPartModel {

	@Override
	protected void open() {
		System.out.println("打开纸币器");
	}

	@Override
	protected void reset() {
		System.out.println("重置纸币器");
	}

	@Override
	protected void enable() {
		System.out.println("使能纸币器");
	}

	@Override
	protected void select() {
		System.out.println("查询纸币器");
	}

	@Override
	protected void startThread() {
		System.out.println("开启纸币器轮训线程");
	}
}

      最后我们就可以在主方法里面,按照顺序进行调用了。请看如下代码:

public class TestMain {

	public static void main(String[] args) {
		
		CoinModel coinModel=new CoinModel();
		ArrayList<String> sequence=new ArrayList<String>();
		sequence.add("open");
		sequence.add("reset");
		sequence.add("enable");
		sequence.add("select");
		sequence.add("startThread");
		
		coinModel.setSequence(sequence);
		coinModel.run();
	}
}

      通过上面的代码我可以很轻松的实现按照顺序设置各个货币器的状态,但是如果现在需求有变更,我希望能够按照任意的顺序去调用不同的方法,实现一种可定制化的需求。这个时候应该怎么办?现在轮到建造者模式出厂了,同样我们还是需要首先定义一个基类的建造者CurrentPartBuild,代码如下:

public abstract class CurrentPartBuild {

	protected abstract void setSequence(ArrayList<String> sequence);
	protected abstract CurrentPartModel getModel();
}

      然后分别实现硬币器和纸币器的建造者,代码如下:

public class CoinBuild extends CurrentPartBuild {

	CoinModel coinModel=new CoinModel();
	
	@Override
	protected void setSequence(ArrayList<String> sequence) {
		this.coinModel.setSequence(sequence);
	}

	@Override
	protected CurrentPartModel getModel() {
		return this.coinModel;
	}
}
public class BillBuild extends CurrentPartBuild {

	BillModel billModel=new BillModel();
	
	@Override
	protected void setSequence(ArrayList<String> sequence) {
		this.billModel.setSequence(sequence);
	}

	@Override
	protected CurrentPartModel getModel() {
		return this.billModel;
	}
}

  最后我们再来安排一位导演负责整个建筑顺序的监督者,就好比是一位包工头,其他的建造者都需要听从包工头的安排进行工作。导演类的代码如下:

public class Director {

	private ArrayList<String> sequence=new ArrayList<String>();
	CoinBuild coinBuild=new CoinBuild();
	BillBuild billBuild=new BillBuild();
	
	public CoinModel getCoinOneModel(){
		this.sequence.clear();
		this.sequence.add("open");
		this.sequence.add("reset");
		
		this.coinBuild.setSequence(this.sequence);
		return (CoinModel)this.coinBuild.getModel();
	}
	
	public CoinModel getCoinTwoModel(){
		this.sequence.clear();
		this.sequence.add("enable");
		this.sequence.add("select");
		
		this.coinBuild.setSequence(this.sequence);
		return (CoinModel)this.coinBuild.getModel();
	}
	
	public BillModel getBillOneModel(){
		this.sequence.clear();
		this.sequence.add("open");
		this.sequence.add("reset");
		
		this.billBuild.setSequence(this.sequence);
		return (BillModel)this.billBuild.getModel();
	}
	
	public BillModel getBillTwoModel(){
		this.sequence.clear();
		this.sequence.add("enable");
		this.sequence.add("select");
		
		this.billBuild.setSequence(this.sequence);
		return (BillModel)this.billBuild.getModel();
	}
}

  通过上面导演类的安排,我们就可以很优雅的建筑不同顺序的调用,是不是突然发现建造者的强大之处呢?其实我们的项目场景里面有很多地方都需要用到它。大家也需要可能会问建造者跟工厂模式有什么区别呢?其实区别很简单,工厂模式注重的是创建过程,而建造者模式注重的是调用顺序。

      好了,今天的博客就到这里,see you!

以上是关于设计模式之建造者模式的主要内容,如果未能解决你的问题,请参考以下文章

23种设计模式之建造者模式代码实例

设计模式从青铜到王者第八篇:创建型模式之建造者模式(BuilderPattern)

《设计模式》之建造者模式(Builder)

创建型模式之建造者模式

设计模式之建造者模式

设计模式之建造者模式(builder)