1 引子
通常我们构造一个人的对象,都是通过new关键字来的如
new Person();
如果还要赋予人的性别,年龄,身高,体重等属性,一般都是通过get/set或者构造函数来实现,如
public class Person {
private String sex;
private int age;
private String height;
public Person(String sex, int age, String height) {
this.sex = sex;
this.age = age;
this.height = height;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getHeight() {
return height;
}
public void setHeight(String height) {
this.height = height;
}
public String toString(){
return "此人性别为:" + sex + ",年龄为:" + age + ", 身高为:" + height;
}
}
为了明确类的职责,从性别的角度来分,人可以分为男人和女人,可分别作为两个对象,如
class Women extends Person{
public Women(int age, String height) {
super("0", age, height); // 参数0表示女性
}
}
class Man extends Person{
public Man(int age, String height) {
super("1", age, height); // 参数1表示男性
}
}
通过面向对象的继承特性复用Person类的年龄和身高属性。
这是一个很宏观的构造对象的过程,从微观角度看,人本身由各个器官和组织构成,构造的过程可细分为好几部分,每部分可分别作为一个对象存在。这里把构造人的过程简化为三步:构造头脑,构造身体和构造脚。注意,男人和女人都要经过这三个步骤但头脑、身体和脚却不相同。因此可通过类似工厂方法来实现微观的构造过程:
男人Man类:
public class Man extends Person{
private ManHead manHead;
private ManBody manBody;
private ManFoot manFoot;
public Man(int age, String height, ManHead manHead,ManBody manBody, ManFoot manFoot) {
super("1", age, height);
this.manHead = manHead;
this.manBody = manBody;
this.manFoot = manFoot;
System.out.println(this + ".完成构造一个男人的过程!");
}
}
class ManHead{
public ManHead(){
System.out.println("创建男人的头部,脖子那有喉结...");
}
}
class ManBody{
public ManBody(){
System.out.println("创建男人的身体,有JJ...");
}
}
class ManFoot{
public ManFoot(){
System.out.println("创建男人的脚,脚一般都狠长...");
}
}
女人Women类:
public class Women extends Person{
private WomenHead womenHead;
private WomenBody womenBody;
private WomenFoot womenFoot;
public Women(int age, String height, WomenHead womenHead, WomenBody womenBody, WomenFoot womenFoot) {
super("0", age, height);
this.womenHead = womenHead;
this.womenBody = womenBody;
this.womenFoot = womenFoot;
System.out.println(this + ".完成构造一个女人的过程!");
}
}
class WomenHead{
public WomenHead(){
System.out.println("创建女人的头部,脖子那没有喉结...");
}
}
class WomenBody{
public WomenBody(){
System.out.println("创建女人的身体,有胸部...");
}
}
class WomenFoot{
public WomenFoot(){
System.out.println("创建女人的脚,脚一般都较小...");
}
}
抽象构造过程:
public interface Builder {
void head();
void body();
void foot();
Person createPerson();
}
构造男人过程工厂:
public class BuilderMan implements Builder {
private ManHead manHead;
private ManBody manBody;
private ManFoot manFoot;
// step one
@Override
public void head(){
manHead = new ManHead();
}
// step two
@Override
public void body(){
manBody = new ManBody();
}
// step three
@Override
public void foot() {
manFoot = new ManFoot();
}
@Override
public Person createPerson() {
return new Man(1, "170cm", manHead, manBody, manFoot);
}
}
构造女人工厂类:
public class BuilderWomen implements Builder {
private WomenHead womenHead;
private WomenBody womenBody;
private WomenFoot womenFoot;
// step one
@Override
public void head(){
womenHead = new WomenHead();
}
// step two
@Override
public void body(){
womenBody = new WomenBody();
}
// step three
@Override
public void foot() {
womenFoot = new WomenFoot();
}
@Override
public Person createPerson() {
return new Women(1, "160cm", womenHead, womenBody, womenFoot);
}
}
为了对外提供统一的方法,可通过指导者来传达客户的命令:
指导者:
public class Director {
public Person createPerson(Builder builder){
builder.head();
builder.body();
builder.foot();
return builder.createPerson();
}
}
客户端:
public class Client {
public static void main(String[] args) {
Director director = new Director();
director.createPerson(new BuilderMan());
System.out.println("=========================");
director.createPerson(new BuilderWomen());
}
}
在这里,指导者Director是关键。利用依赖倒置的原则屏蔽建造的细节,根据传入的参数来决定建造哪个对象,从而对外只提供一个指导者,客户端毫无感知建造的细节,这种把对象的创建过程和对象的表示分离开来的模式称为建造者模式。
运行结果
创建男人的头部,脖子那有喉结...
创建男人的身体,有JJ...
创建男人的脚,脚一般都狠长...
此人性别为:1,年龄为:1, 身高为:170cm.完成构造一个男人的过程!
=========================
创建女人的头部,脖子那没有喉结...
创建女人的身体,有胸部...
创建女人的脚,脚一般都较小...
此人性别为:0,年龄为:1, 身高为:160cm.完成构造一个女人的过程!
2 建造者模式原理
《大话设计模式》中这样定义建造者模式:将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。即通过“依赖倒置”来解耦构造过程和表现形式;构造过程通过接口Builder定义构造步骤,BuilderMan和BuilderWomen定义不同对象的构造细节;通过Director类给客户端提供方法得到不同的表示。
3 建造者模式特点
建造者模式有什么优点?
建造者模式最大的优点如它的定义一样,把构建的过程和表现形式分离开,客户端只需要通过统一的方法,根据传入的参数决定不同的构造对象从而得到不同形式的对象。
熟悉模板模式的人会觉得两者有点相似,当把head()/body()/foot()方法放入createPerson(),就与我们之前讲过的模板模式非常类似。模板模式和建造者模式有本质的区别,模板模式是行为型模式,关注的是流程化的行为,而建造者模式是创建型模式,关注的是复杂对象的建造过程和创建结果的表现形式。
建造者模式有什么缺点?
如果对象的建造过程容易发生变化,则对类的维护较困难。
4 建造者模式适用场景
《大话设计模式》中指出:建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时使用的模式。即当创建对象的过程较复杂,而同样创建过程需得到不同对象的情况,可利用建造者模式。
5 参考资料
《大话设计模式》