建造者模式是较为复杂的建立型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的建立过程分离,客户端无须知道复杂对象的内部组成部分与装配方式,只须要知道所需的建造者类型便可。建造者模式关注一步一步地建立一个复杂对象,不一样的具体建造者定义了不一样的建立过程,且具体建造者相互独立,增长新的建造者很是方便,无须修改已有代码,系统具备较好的扩展性。java
建造者模式中用到了复杂对象这个概念。编程
复杂对象就是指那些包含多个成员变量的对象,这些成员变量也叫部件或者零件,例如汽车包括方向盘,发动机,轮胎等 ,
汽车就是复杂对象,方向盘,发动机以及轮胎就是汽车的部件。微信
建造者模式:将一个复杂的对象的构建与它的表示分离,使得一样的构建过程能够建立不一样的表示。ide
建造者模式是一种对象建立型模式。函数
建造者模式包含如下四个角色:post
Builder
(抽象建造者):为建立一个产品Product对象的各个部件指定抽象接口,在该接口中通常声明两类方法,一类是buildXXX()
方法,用于建立复杂对象的各个部分(部件),另外一类是是getResult()
,用于返回复杂对象。Builder
既能够是抽象类,也能够是接口ConcreteBuilder
(具体建造者):实现了Builder
接口或者继承了Builder
类,实现各个部件的具体构造和装配方法,定义并明确其所建立的复杂对象,也能够提供一个方法返回建立好的复杂对象Product
(产品角色):是被构建的复杂对象,包含多个组成部件,具体建造者建立该产品的内部表示并定义其装配过程Director
(指挥者):指挥者又叫导演类,复杂安排复杂对象的建造次序,指挥者与抽象建造者之间存在关联关系,能够在其construct()
建造方法中调用建造者对象的部件构造以及装配方法,完成复杂对象的建造。客户端通常只须要与导演类进行交互,在客户端肯定具体建造者的类型,并实例化具体建造者对象,而后经过导演类的构造函数或者setter将该对象传入导演类中bulidXXX
的数量,同时声明相似getResult
返回产品角色对象的方法buildXXX
方法construct
的方法给外界,调用具体建造者的方法并返回产品角色对象通常来讲Product
是一个复杂对象,典型的实现以下:测试
class Product { private type1 part1; private type2 part2; private type3 part3; //getter + setter ... }
其中type1
,type2
等指各类不一样的类型,通常来讲会有嵌套类。优化
抽象建造者的典型实现以下:ui
abstract class Builder { protected Product product = new Product(); public abstract void buildPart1(); public abstract void buildPart2(); public abstract void buildPart3(); public Product getResult() { return product; } }
抽象建造者中声明了一系列buildXXX
方法,用于建立Product
的各个部件,具体建立过程在ConcreteBuilder
中实现,getResult()
返回已建立完成的Product
。this
ConcreteBuilder
实现了Builder
中的buildXXX
方法,经过调用Product
的setter来实现给产品对象的各部分赋值。
不一样的ConcreteBuilder
在实现buildXXX
时将有所区别,好比传入Product
的setter参数的不一样。
另外在有些ConcreteBuilder
中某些buildXXX
无须实现(提供一个空实现),这些对客户端来讲无须关心,客户端只须要知道具体建造者的类型便可。
典型实现以下:
class ConcreteBuilder extends Builder { public void buildPart1() { product.setPart1("part1"); } public void buildPart2() { product.setPart2("part2"); } public void buildPart3() { product.setPart3("part3"); } }
Director
类主要有两个做用:
buildXXX
方法是否被调用,以及调用时的前后次序等等指挥者针对抽象建造者编程,客户端只须要知道具体建造者的类型,便可经过指挥者调用建造者的相关方法,返回一个完整的产品对象。典型实现以下:
class Director { private Builder builder; public Director(Builder builder) { this.builder = builder; } public void setBuilder(Builder builder) { this.builder = builder; } public Product construct() { builder.buildPart1(); builder.buildPart2(); builder.buildPart3(); return builder.getResult(); } }
建立具体建造者并传入导演类做为构造方法参数,而后调用construct
便可获取产品对象:
public static void main(String[] args) { Director director = new Director(new ConcreteBuilder()); Product product = director.construct(); System.out.println(product.getPart1()); }
游戏角色的建立:不一样的角色具备差异极大的外部特征,并且要求随着游戏的进行会不断出现新的角色,也就是说扩展性要好。这里例子简化就建立三个角色:英雄,天使与恶魔,使用建造者模式进行设计。
设计以下:
Actor
ActorBuilder
HeroBuilder
+AngelBuilder
+DevilBuilder
ActorController
代码以下:
// 复杂产品 class Actor { private String type; private String face; private String costume; private String hairstyle; //getter and setter ... } //抽象建造者 abstract class ActorBuilder { protected Actor actor = new Actor(); public abstract void buildType(); public abstract void buildFace(); public abstract void buildCostume(); public abstract void buildHairstyle(); public Actor createActor() { return actor; } } //具体建造者 class HeroBuilder extends ActorBuilder { public void buildType(){ actor.setType("英雄"); } public void buildFace(){ actor.setFace("英俊"); } public void buildCostume(){ actor.setCostume("盔甲"); } public void buildHairstyle(){ actor.setHairstyle("飘逸"); } } class AngleBuilder extends ActorBuilder { public void buildType(){ actor.setType("天使"); } public void buildFace(){ actor.setFace("漂亮"); } public void buildCostume(){ actor.setCostume("白裙"); } public void buildHairstyle(){ actor.setHairstyle("披肩长发"); } } class DevilBuilder extends ActorBuilder { public void buildType(){ actor.setType("恶魔"); } public void buildFace(){ actor.setFace("帅气"); } public void buildCostume(){ actor.setCostume("黑衣"); } public void buildHairstyle(){ actor.setHairstyle("红色"); } } // 指挥者类 class ActorController { public Actor construct(ActorBuilder builder) { builder.buildType(); builder.buildFace(); builder.buildHairstyle(); builder.buildCostume(); return builder.createActor(); } }
测试类:
public class Test { public static void main(String[] args) { ActorBuilder builder = new AngleBuilder(); ActorController controller = new ActorController(); Actor actor = controller.construct(builder); System.out.println(actor.getType()); System.out.println(actor.getCostume()); System.out.println(actor.getHairstyle()); System.out.println(actor.getFace()); } }
Director
其实Director
是能够省略的,直接与Builder
合并,在Builder
中提供相似Direcotr
中的construct()
方法,并定义为静态方法,如:
abstract class ActorBuilder { protected static Actor actor = new Actor(); public abstract void buildType(); public abstract void buildFace(); public abstract void buildCostume(); public abstract void buildHairstyle(); public static Actor build(ActorBuilder builder) { builder.buildType(); builder.buildFace(); builder.buildHairstyle(); builder.buildCostume(); return actor; } }
同时客户端代码修改以下:
Actor actor = ActorBuilder.build(new AngleBuilder()); //Actor actor = ActorBuilder.build(new HeroBuilder()); //Actor actor = ActorBuilder.build(new DevilBuilder());
再简单一点的能够省略createActor
中的参数:
abstract class ActorBuilder { protected Actor actor = new Actor(); public abstract void buildType(); public abstract void buildFace(); public abstract void buildCostume(); public abstract void buildHairstyle(); public Actor build() { buildType(); buildFace(); buildHairstyle(); buildCostume(); return actor; } }
同时客户端简化以下:
Actor actor = new AngleBuilder().build();
这两种方式简化了系统结构的同时又不影响灵活性以及可扩展性,可是加剧了抽象建造者的职责,若是build
方法较为复杂,待构建的产品组成部分较多,建议仍是将其单独封装在Director
中,这样更加符合SRP(单一权责原则)。
钩子方法是一种能够控制是否调用某个buildXXX
的方法,特征以下:
boolean
isXXX
例如修改ActorBuilder
以下:
abstract class ActorBuilder { protected Actor actor = new Actor(); public abstract void buildType(); public abstract void buildFace(); public abstract void buildCostume(); public abstract void buildHairstyle(); public boolean isBareheaded() { return false; } public Actor createActor() { return actor; } }
并修改DevilBuilder
,覆盖默认方法:
class DevilBuilder extends ActorBuilder { public void buildType(){ actor.setType("恶魔"); } public void buildFace(){ actor.setFace("帅气"); } public void buildCostume(){ actor.setCostume("黑衣"); } public void buildHairstyle(){ actor.setHairstyle("红色"); } public boolean isBareheaded(){ return true; } }
最后修改ActorController
:
class ActorController { public Actor construct(ActorBuilder builder) { builder.buildType(); builder.buildFace(); builder.buildCostume(); if(builder.isBareheaded()) builder.buildHairstyle(); return builder.createActor(); } }
相比起以前的ActorController
多了一次判断,测试以下:
public static void main(String[] args) { ActorController controller = new ActorController(); Actor actor = controller.construct(new AngleBuilder()); System.out.println(actor.getType()); System.out.println(actor.getCostume()); System.out.println(actor.getHairstyle()); System.out.println(actor.getFace()); System.out.println(); actor = controller.construct(new DevilBuilder()); System.out.println(actor.getType()); System.out.println(actor.getCostume()); System.out.println(actor.getHairstyle()); System.out.println(actor.getFace()); }
输出以下:
在实际应用中Director
较少出现,一般只有Builder
以及Product
,并且Builder
是做为Product
的内部类,提供一系列set
方法,这些set
方法返回一个Builder
方便后续调用,最后以一个build()
结尾,好比OkHttp中的Request
/OkHttpClient
:
OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(5000,TimeUnit.MILLISECONDS) .readTimeout(10,TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url("https://xxx") .post(requestBody) .build();
若是以为文章好看,欢迎点赞。
同时欢迎关注微信公众号:氷泠之路。