• 设计模式-建造者模式


    一、建造者模式的的核心思想

    工厂类提供了生产单个产品的功能,而建造者模式则可以将各种产品集中起来进行统一管理,建造者模式也是工厂模式的扩展,区别是它将各种产品集中了起来。

    建造者模式用来创建复合对象,并把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象。所谓复合对象,指有别于一般的对象,该对象具有不同的复合属性。比如我们把一个农场看成一个复合对象,是因为该农场由多个猪、鸡、牛、羊组成的,这些单个的产品可能因为农场主的不同而不同,但这些不同的产品最终都能被组装成为一个农场。这些不同的产品我们可称为农场的复合属性,同样可称该农场为一个复合对象。

    实际上,建造者模式等价于多个工厂方法模式加上其测试类所拥有的功能,即它不仅负责创建各个产品,还负责提供计算价钱等管理功能。使用建造者模式表示的结构如下图所示。
    在这里插入图片描述

    建造者类Far5 提供了生产各种产品的功能,并根据生产的数量添加到一个存储数组 List中同时提供了计算该农场销售价格的方法sum()。完整的代码如下程序所示:

    建造者模式 Farm5.java

    package creation.builder;
    
    import java.util.ArrayList;
    import java.util.List;
    
    
    /**
    * @author Minggg 建造者模式
    */
    public class Farm5 {
    
    	private List<Animal> list = new ArrayList<Animal>();
    	
    	public void producePig(int count) {
    		for (int i = 0; i < count; i++){
    			list.add(new Pig())
    		}
    	}
    
    	public void produceChicken(int count){
    		for (inti=0;i< count; i++){
    			list.add(new Chicken());
    		}
    	}
    
    	public void produceCattle(int count){
    		for (int i= 0; i< count; i++){
    			list.add(new Cattle());
    		}
    	}
    
    	public void produceSheep(int count)
    		for (int i=0;i < count; i++){
    			list.add(new Sheep());
    		}
    	}
    
    	public int sum() {
    		int money = 0;
    		for(Animal animal:list){
    			money += animal.sale();
    		}
    		return money;
    	}
    
    }
    
    

    此时我们可以调用该工厂类直接创建不同数量的产品,然后一次性取得销售的总价格,如下程序所示:

    测试类Farm5Test.java

    package creation.builder;
    
    public class Farm5Test {
    
    	public static void test() {
    		// 创建工厂
    		Farm5 farm = new Farm5();
    		farm.producePig(20);//生产20 头猪
    		farm.produceChicken(1000);//生产1000 只鸡
    		farm.produceCattle(10);// 生产10 头牛
    		farm.produceSheep(50);// 生产50只羊
    		
    		//计算总收入
    		int sum = farm.sum();
    		System.out.printIn("Fram5 总收入:"+sum);
    	}
    	
    	public static void main(String[] args)
    		Farm5Test.test();
    	}
    
    }
    
    

    这里使用 Farm5 的方式比 Farm3简单得多,不需要在外部管理各种数量的产品,这种管理的工作全部交给了工厂类去实现,这就是建造者类的作用。

    二、何时使用建造者模式

    我们上面提到了 Builder 模式与工厂模式一样,都属于对象的创建型模式,都用来创建类的对象。但它们存在本质的区别:

    • 在工厂模式里,我们无须关心产品的各部分是如何被创建的,也就是说,工厂式关注的是整个产品。
    • 在 Builder 模式里,会把产品的创建过程抽象为多个部分。也就是说,Builder 模式关注的是产品各组成部分的创建过程。

    因为上述关注点的不一样,工厂模式创建的产品是一个单一产品;Builder 模式创建的是一个复合产品。

    简单地说,在具体的应用中,我们选用工厂模式来创建对象还是选用Builder 模式来创建对象,完全取决于我们的关注点。

    比如同为创建一辆汽车,如果我们只需关注从工厂里造出的这一辆汽车本身(然后加以使用),我们就可以使用工厂模式来创建该汽车。

    但如果我们还应该关注该汽车的各部分是怎么造出来的(或者说,不同的工厂对产品的各部分的造法不一样),我们就应该使用 Builder 模式。

    三、Java中的应用–字符串建造者类 StringBuilder

    在Java API中,字符串处理类 StringBuilder 就采用了建造者模式。它的产品就是追加的各种数据,包括字符串、int、long、数组等。该类继承自 AbstractStringBuilder,其中包含了数组 char value[]用来存储各种数据,并提供了一系列的 append()、delete()、insert()等函数用来增加、修改和删除名种数据,因此 StringBuilder 提供了构造该数据集的各部分的操作,这属于建造者模式。

    其主要的代码如程序下所示:
    字符串建造者类StringBuilder.iava

    package iava.lang;
    
    public final class StringBuilder extends AbstractStringBuilder implements java.io.Serializable, CharSequence {
    
    	public StringBuilder() {
    		super(16);
    	}
    	
    	public StringBuilder(int capacity) {
    		super(capacity);
    	}
    	
    	public StringBuilder(String str) {
    		super(str.length()+ 16);
    		append(str);
    	}
    
    	public StringBuilder(CharSequence seq) {
    		this(seq.length()+ 16);
    		append(seq);
    	}
    	
    	public StringBuilder append(Object obj) {
    		return append(String.valueOf(obj));
    	}
    	
    	public StringBuilder append(String str) {
    		super.append(str);
    		return this;
    	}
    	
    	private StringBuilder append(StringBuilder sb) {
    		if (sb == null) {
    			return append("nul!");
    		}
    		int len = sb.length();
    		int newcount = count + len;
    	
    		if(newcount > value.length) {
    			expandCapacity(newcount);
    		}
    		sb.getChars(0, len, value, count);
    		count = newcount;
    		return this;
    	}
    
    	public StringBuilder append(StringBuffer sb){
    		super.append(sb);
    		return this;
    	}
    
    	public StringBuilder append(CharSequence s){
    		if(s =- null)
    			s = "nul";
    		if(s instanceof String) {
    			return this.append((String)s);
    		}
    		if (s instanceof StringBuffer) {
    			return this.append((StringBuffer)s);
    		}
    		if(s instanceof StringBuilder) {
    			return this.append((StringBuilder)s);
    		}
    		return this.append(s, 0, s.length();
    	}
    
    	public StringBuilder append(CharSequence s, int start, int end) {
    		super.append(s, start, end);
    		return this;
    	}
    
    	public StringBuilder append(char str[]){
    		super.append(str);
    		return this;
    	}
    
    	public StringBuilder append(char str], int offset, int len) {
    		super.append(str, offset, len);
    		return this;
    	}
    
    	public StringBuilder append(boolean b) {
    		super.append(b);
    		return this;
    	}
    	
    	public StringBuilder append(char c) {
    		super.append(c);
    		return this;
    	}
    	
    	public StringBuilder append(int i){
    		super.append(i);
    		return this;
    	}
    	
    	public StringBuilder append(long lng) {
    		super.append(lng);
    		return this;
    	}
    	
    	public StringBuilder append(float f){
    		super.append(f);
    		return this;
    	}
    	
    	public StringBuilder append(double d) {
    		super.append(d);
    		return this;
    	}
    	
    	public StringBuilder delete(int start, int end) {
    		super.delete(start, end);
    		return this;
    	}
    
    	public StringBuilder replace(int start, int end, String str) {
    		super.replace(start, end, str);
    		return this;
    	}
    	
    	public StringBuilder insert(int index, char strl], int offset, int len) {
    		super.insert(index, str, offset, len);
    		return this;
    	}
    	
    	public String toString(){
    		return new String(value, 0, count);
    	}
    
    }
    
    

    以上建造者类的产品是各种类型的数据,如String、int、long、char 等,它们组合起来构成了整个数据集。

    四、Java中的应用–进程建造者类 ProcessBuilder

    与 StringBuilder 建造者类一样,ProcessBuilder也是建造者类,它管理的数据对象是一系列的命令,这些进程的命令存储在command列表对象中,对该列表对象的创建和管理就构成了对该复合对象进行管理的功能。

    完成管理后,可以调用star()来统一启动该复合对象中的所有命令,其主要的代码如下程序所示:

    进程建造者类ProcessBuilder.java

    package java.lang;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.atil.Map;
    
    public final class ProcessBuilder {
    
    	private List<String> command;
    	private File directory;
    	private Map<String,String> environment;
    	private boolean redirectErrorStream;
    	
    	public ProcessBuilder(List<String> command){
    		if(command == null) {
    			throw new NullPointerException();
    		}
    		this.command = command;
    	}
    	public ProcessBuilder(String.. command){
    		this.command = new ArrayList<String>(command.length);
    		for (String arg : command){
    			this.command.add(arg);
    		}
    	}
    	
    	public ProcessBuilder command(List<String> command) {
    		if (command == null) {
    			throw new NullPointerException();
    		}
    		this.command = command;
    		return this;
    	}
    
    	public ProcessBuilder command(String.. command) {
    		this.command = new ArrayList<String>(command.length);
    		for (String arg : command) {
    			this.command.add(arg);
    		}
    		return this;
    	}
    	
    	public List<String> command() {
    		return command;
    	}
    
    	public Process start() throws IOException {
    		String[] cmdarray = command.toArray(new String[command.size()]);
    		for (String arg : emdarray) {
    			if (arg == null) {
    				throw new NulPointerException();
    			}
    		}
    		String prog = cmdarray[0];
    		SecurityManager security = System.getSecurityManager();
    		if (security != null) {
    			security.checkExec(prog);
    		}
    		String dir = directory == null ? null : directory.toString();
    		try {
    			return ProcessImplstart(emdarray, environment, dir, redirectErrorStream);
    		}catch (IOException e){
    			throw new IOException("Cannot run program \" + prog + "\""+ (dir == nul! ? "" ; " (in directory \"" + dir + "\’)")+":"+e.getMessage, e);
    		}
    	}
    }
    
    
  • 相关阅读:
    如何看待Unity新的收费模式?
    【Unity3D编辑器拓展】Unity3D的IMGUI、GUI、GUILayout、EditorGUI、EditorGUILayout、OnGUI【全面总结】
    欧冠比赛数据集(梅西不哭-离开巴萨也可能再创巅峰)
    Mysql学习笔记--基础
    线代 | 考研线性代数 解题方法汇总(非知识点汇总)
    构建器模式-C++实现
    微服务平滑迁移上云最佳实践
    一篇文章让你真正搞懂epoll机制
    Nacos注册中心配置安装和问题解决
    [附源码]计算机毕业设计JAVAjsp求职招聘平台开发
  • 原文地址:https://blog.csdn.net/qq_35885952/article/details/139621666