zoukankan      html  css  js  c++  java
  • 设计模式之建造者模式

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

          下面跟大家分享一个笔者前段时间在项目里面遇到的一个问题场景:售货机大家都应该听说过,在售货机上面都有一个可以收取硬币或者纸币的货币器(后面笔者为了代码陈述方便,会将货币器拆分为硬币器和纸币器),别看我们在购买一瓶饮料的时候,只需要简简单单的投入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!

  • 相关阅读:
    二维数组和最大字数组求取 2
    spring冲刺第七天
    spring冲刺第六天
    寻找水王
    spring冲刺第五天
    spring冲刺第四天
    spring冲刺第三天
    spring冲刺第二天
    大道至简读书笔记3
    spring冲刺第一天
  • 原文地址:https://www.cnblogs.com/xiaocai20091687/p/xiaocai_design_six.html
Copyright © 2011-2022 走看看