建造者模式

《大话设计模式》第13章读书笔记,介绍建造者模式

Posted by GrayWind on November 13, 2018

建造者模式(Builder)将一个复杂对象的构造与它的表示分离,使得同样的构造过程可以创建不同的表示。如果我们用了建造者模式,那么用户就只需要指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需要知道了。

什么时候需要使用建造者模式?

主要用于创建一些复杂的对象,这些对象内部构造间的建造顺序通常是稳定的,但对象内部的构造通常面临着复杂的变化。它的好处是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了。

先来看一下建造者模式的结构图

builder

建造者是一个接口或者抽象类,由具体建造者来复杂构造和装配具体的产品的部件。而用户在使用时,是通过指挥者Director来间接调用接口。

下面来看一个实际的例子,假设现在要新建一个Human对象,它的属性如下,并且有展示方法,这个Human对象就是实际要建造的具体产品

public class Human {
	private String height;
	private String weight;
	private String iq;
	private String age;
	
	public void show() {
		System.out.println("开始打印");
		System.out.println(height);
		System.out.println(weight);
		System.out.println(iq);
		System.out.println(age);
		System.out.println("打印结束");
	}

	public String getHeight() {
		return height;
	}

	public void setHeight(String height) {
		this.height = height;
	}

	public String getWeight() {
		return weight;
	}

	public void setWeight(String weight) {
		this.weight = weight;
	}

	public String getIq() {
		return iq;
	}

	public void setIq(String iq) {
		this.iq = iq;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

}

然后是抽象建造者,它需要声明装配各个部件也就是属性的方法,和返回具体对象的抽象方法

public interface BuildHuman {
	public void buildHead();
	public void buildHeight();
	public void buildWeight();
	public void buildAge();
	public Human createHuman();
}

实际建造者就是接口的实现类,根据需要不同,我们可以定义不同的具体实现类,比如下面的建造一个高智商对象和建造一个胖对象

public class SmartManBuilder implements BuildHuman {
	private Human human;
	
	public SmartManBuilder() {
		human = new Human();
	}
	
	@Override
	public void buildHead() {
		human.setIq("智商180");
	}

	@Override
	public void buildHeight() {
		human.setHeight("身高170");
	}

	@Override
	public void buildWeight() {
		human.setWeight("体重130");
	}

	@Override
	public void buildAge() {
		human.setAge("年龄23");
	}

	@Override
	public Human createHuman() {
		return human;
	}

}

public class FatManBuilder implements BuildHuman {
	private Human human;
	
	public FatManBuilder() {
		human = new Human();
	}
	
	@Override
	public void buildHead() {
		human.setIq("智商100");
	}

	@Override
	public void buildHeight() {
		human.setHeight("身高180");
	}

	@Override
	public void buildWeight() {
		human.setWeight("体重180");
	}

	@Override
	public void buildAge() {
		human.setAge("年龄25");
	}

	@Override
	public Human createHuman() {
		return human;
	}

}

指挥者需要做的是,根据用户给出的实际建造者,调用具体构造和拼装方法,最后返回实际产品

public class PersonDirector {
	public static Human createHumanByDirecotr(BuildHuman bh) {
		bh.buildAge();
		bh.buildHead();
		bh.buildHeight();
		bh.buildWeight();
		return bh.createHuman();
	}
}

测试代码如下

	public static void main(String[] args) {
		BuildHuman bh = new SmartManBuilder();
		Human smartHuman = PersonDirector.createHumanByDirecotr(bh);
		smartHuman.show();
		
		bh = new FatManBuilder();
		Human fatHuman = PersonDirector.createHumanByDirecotr(bh);
		fatHuman.show();
	}

从测试代码中,我们可以看出,用户只需要给出具体的建造者就可以通过指挥者获取具体产品Human,而其中具体的调用和构造细节一概不知,而指挥者中只需要针对抽象的建造者接口进行编码调用,无需关心其中的具体实现,降低了耦合性。