建造者模式:将一个复杂对象与它表示分离,使得同样的构建过程可以创建不同的表示。例子来自于《大话设计模式》
使用了建造者模式,用户只需要指定需要建造的类型就可以得到他们,而具体建造的过程和细节就不需要知道了。
最简答的例子:写一个用笔画小人的程序,小人固定要画六个部位,头,身体,左手,右手,左脚,右脚
要画的部位是固定的,所以先写一个确定只画这几个部位的抽象父类。(用接口也可以)让子类继承,那么子类也只能按这个要求画
PersonBuilder:人的构造器
public abstract class PersonBuilder { public abstract void buildHead(); public abstract void buildBody(); public abstract void buildArmLeft(); public abstract void buildArmRight(); public abstract void buildLegLeft(); public abstract void buildLegRight(); }
现在我想画一个瘦子,那么创建一个瘦子类PersonThinBuilder,瘦子类继承父类PersonBuilder,因为父类是抽象类,强制子类重写抽象方法。
PersonThinBuilder:
public class PersonThinBuilder extends PersonBuilder{ @Override public void buildHead() { System.out.println("瘦人尖嘴猴腮"); } @Override public void buildBody() { System.out.println("瘦人看不到肚子"); } @Override public void buildArmLeft() { System.out.println("瘦人细左臂"); } @Override public void buildArmRight() { System.out.println("瘦人细右臂"); } @Override public void buildLegLeft() { System.out.println("瘦人细左腿"); } @Override public void buildLegRight() { System.out.println("瘦人细右腿"); } }
同理,要画一个胖子也要新建一个胖子子类
PersonFatBuilder:
public class PersonFatBuilder extends PersonBuilder{ @Override public void buildHead() { System.out.println("胖人肥头大耳"); } @Override public void buildBody() { System.out.println("胖人大肚子"); } @Override public void buildArmLeft() { System.out.println("胖人粗左臂"); } @Override public void buildArmRight() { System.out.println("胖人粗右臂"); } @Override public void buildLegLeft() { System.out.println("胖人粗左腿"); } @Override public void buildLegRight() { System.out.println("胖人粗右腿"); } }
为了让客户不需要看到实现,只需要调用即可,我们要创建一个指挥类去画这个人,即将表示分离到到这个指挥类里。
PersonDirector:
public class PersonDirector { private PersonBuilder pb; public PersonDirector(PersonBuilder pb) { this.pb = pb; } public void CreatePerson(){ pb.buildHead(); pb.buildBody(); pb.buildArmLeft(); pb.buildArmRight(); pb.buildLegLeft(); pb.buildLegRight(); } }
测试方法:
PersonMain
public class PersonMain { public static void main(String[] args) { PersonThinBuilder ptb = new PersonThinBuilder(); PersonDirector pdThin = new PersonDirector(ptb); pdThin.CreatePerson(); } }客户只需要告诉我要一个什么样的人,我就能给他画出来。
就类似于麦当劳吃汉堡,具体味道怎么调,配料怎么配,原料怎么买,价格怎么定店员都不需要知道。店员只需要按公司的要求去按步骤做就可以了。
当一个对象的构建过程非常复杂,且步骤单不会变化,就适合用建造者模式。
再看一个稍微复杂一点点点的例子。
设计思路:
产品:Product
public class Product { List parts = new ArrayList(); public void add(String part){ parts.add(part); } public void show(){ System.out.println("产品创建----"); for (Object part : parts) { System.out.println(part); } } }
因为步骤不变,所以用虚拟类确定要做的步骤
抽象建造者:Builder:
public abstract class Builder { public abstract void buildPartA(); public abstract void buildPartB(); public abstract Product GetResult(); }
该类确定了步骤是两部分buildPartA和buildPartB,还提供了一个方法GetResult去返回最后的结果产品。用抽象方法就强制要求其他人必须重写这些方法,即必须按我要求的步骤来。
指挥者类:指挥建造过程
Director:
public class Director { public void Construct(Builder builder){ builder.buildPartA(); builder.buildPartB(); } }
现在我们有第一类产品:
ConcreateBuilder1:
public class ConcreateBuilder1 extends Builder { private Product product = new Product(); @Override public void buildPartA() { product.add("部件A"); } @Override public void buildPartB() { product.add("部件B"); } @Override public Product GetResult() { return product; } }
继承Builder,强制性重写Builder的抽象方法。步骤是我规定的,但是步骤里面的细节可以自己决定。
第二类产品:
ConcreateBuilder2:
public class ConcreateBuilder2 extends Builder { private Product product = new Product(); @Override public void buildPartA() { product.add("部件x"); } @Override public void buildPartB() { product.add("部件y"); } @Override public Product GetResult() { return product; } }测试类:Main:
public class Main { public static void main(String[] args) { Director director = new Director(); Builder b1 = new ConcreateBuilder1(); Builder b2 = new ConcreateBuilder2(); director.Construct(b1); Product p1 = b1.GetResult(); p1.show(); director.Construct(b2); Product p2 = b2.GetResult(); p2.show(); } }
运行结果:
产品创建---- 部件A 部件B 产品创建---- 部件x 部件y
建造者模式的好处就是使得建造代码与表示代码分离,由于建造者隐藏了该产品是如何组装的,所以若需要改变一个产品内部表示,只需要再定义一个具体的建造者就可以了。
建造者模式是在当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用的模式。