设计模式-建造者模式

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

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

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

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

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

建造者模式 Farm5.java

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

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

java 复制代码
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

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);
		}
	}
}
相关推荐
In_life 在生活9 小时前
设计模式(四)装饰器模式与命令模式
设计模式
瞎姬霸爱.10 小时前
设计模式-七个基本原则之一-接口隔离原则 + SpringBoot案例
设计模式·接口隔离原则
鬣主任10 小时前
Spring设计模式
java·spring boot·设计模式
程序员小海绵【vincewm】12 小时前
【设计模式】结合Tomcat源码,分析外观模式/门面模式的特性和应用场景
设计模式·tomcat·源码·外观模式·1024程序员节·门面模式
丶白泽12 小时前
重修设计模式-行为型-命令模式
设计模式·命令模式
gjh120816 小时前
设计模式:工厂方法模式和策略模式
设计模式·工厂方法模式·策略模式
shinelord明17 小时前
【再谈设计模式】抽象工厂模式~对象创建的统筹者
数据结构·算法·设计模式·软件工程·抽象工厂模式
前端拾光者18 小时前
前端开发设计模式——责任链模式
设计模式·责任链模式
liang899919 小时前
设计模式之策略模式(Strategy)
设计模式·策略模式
马剑威(威哥爱编程)20 小时前
读写锁分离设计模式详解
java·设计模式·java-ee