举个栗子
问题描述
画一个小人,有头、身体、两手、两脚就可以了。
简单实现
人类
/**
* 人类
* Created by callmeDevil on 2019/7/21.
*/
public class Person {
public void drawHead() {
System.out.print("头 ");
}
public void drawBody() {
System.out.print("身体 ");
}
public void drawHand() {
System.out.print("两手 ");
}
public void drawLeg() {
System.out.print("两脚 ");
}
}
测试
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.drawHead();
person.drawBody();
person.drawHand();
person.drawLeg();
}
}
测试结果
头 身体 两手 两脚
存在问题
画人的时候,头身手脚是必不可少的,不管什么人物,开发时是不能少的。但上面测试代码中时各部分堆积起来,很容易漏写,比如导致健全的人物却少了一条“腿”。而且如果需要在别的地方用这些画小人的程序怎么办?
简单实现2
瘦人类
/**
* 瘦人类
* Created by callmeDevil on 2019/7/21.
*/
public class PersonThinBuilder {
private Person person;
public PersonThinBuilder(Person person){
this.person = person;
System.out.println("瘦人类:");
}
// 建造瘦子
public void build(){
person.drawHead();
person.drawBody();
person.drawHand();
person.drawLeg();
}
}
胖人类
/**
* 胖人类
* Created by callmeDevil on 2019/7/21.
*/
public class PersonFatBuilder {
// 代码与瘦人类类似
}
测试
public class Test2 {
public static void main(String[] args) {
Person person = new Person();
PersonThinBuilder thin = new PersonThinBuilder(person);
thin.build();
System.out.println();
PersonFatBuilder fat = new PersonFatBuilder(person);
fat.build();
}
}
测试结果
瘦人类:
头 身体 两手 两脚
胖人类:
头 身体 两手 两脚
存在问题
这样写的确达到了可以复用这两个画小人的目的,但容易“缺胳膊少腿”的问题,依然没有解决,比如现在需要加一个高个的小人,同样会因为编程不注意,产生同样问题。
建造者模式
定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。 如果使用建造者模式,那么用户就只需指定需要建造的类型就可以得到它们,而具体建造的过程和细节就不需要知道了。
UML图
代码实现
建造人抽象类
/**
* 建造人抽象类
* Created by callmeDevil on 2019/7/21.
*/
public abstract class PersonBuilder {
protected Person person;
public PersonBuilder(Person person){
this.person = person;
}
public abstract void buildHead();
public abstract void buildBody();
public abstract void buildArmLeft();
public abstract void buildArmRight();
public abstract void buildLegLeft();
public abstract void buildLegRight();
}
瘦人类2
/**
* 瘦人类2
* Created by callmeDevil on 2019/7/21.
*/
public class PersonThinBuilder extends PersonBuilder {
public PersonThinBuilder(Person person){
super(person);
}
@Override
public void buildHead() {
System.out.print("头 ");
}
@Override
public void buildBody() {
System.out.print("身体 ");
}
@Override
public void buildArmLeft() {
System.out.print("左手 ");
}
@Override
public void buildArmRight() {
System.out.print("右手 ");
}
@Override
public void buildLegLeft() {
System.out.print("左脚 ");
}
@Override
public void buildLegRight() {
System.out.print("右脚 ");
}
}
胖人类2
/**
* 胖人类2
* Created by callmeDevil on 2019/7/21.
*/
public class PersonFatBuilder extends PersonBuilder{
// 代码与瘦人类2类似
}
建造人指挥者
/**
* 建造人指挥者
* Created by callmeDevil on 2019/7/21.
*/
public class PersonDirector {
private PersonBuilder builder;
public PersonDirector(PersonBuilder builder){
// 用户告诉指挥者需要什么样的小人
this.builder = builder;
}
// 根据用户的选择建造小人
public void createPerson(){
builder.buildHead();
builder.buildBody();
builder.buildArmLeft();
builder.buildArmRight();
builder.buildLegLeft();
builder.buildLegRight();
}
}
测试
public class Test {
public static void main(String[] args) {
Person person = new Person();
PersonDirector thinDirector = new PersonDirector(new PersonThinBuilder(person));
thinDirector.createPerson();
System.out.println();
PersonDirector fatDirector = new PersonDirector(new PersonFatBuilder(person));
fatDirector.createPerson();
}
}
测试结果
瘦人类2:
头 身体 左手 右手 左脚 右脚
胖人类2:
头 身体 左手 右手 左脚 右脚
此时如果需要增加一个高个子和矮个子的小人,应该怎么做?
加两个类,一个高个子类和一个矮个子类,都继承 PersonBuilder ,然后客户端调用即可。
总结
- 主要是用于创建一些复杂的对象,这些对象内部构建间的建造顺序通常是稳定的,但对象内部的构建通常面临着复杂的变化
- 建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品的内部表示,只需要再定义一个具体的建造者就可以了
- 建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式。