设计模式|Builder建造者模式

提供了创建对象的最佳方式
定义
将一个复杂对象的构造与它的表示分离,使得同样的构造过程可以创建不同的表示
主要作用
在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂对象。
用户只需要给出指定复杂对象的类型和内容,建造者模式负责按顺序创建复杂对象(把内部的建造过程和细节隐藏起来)
理解案例
我们购买商品,只需要提供商品的一些标志信息,不需要知道商品如何制造出来的!
一、建造者模式 设计模式|Builder建造者模式
文章图片

指挥者控制工作者来构建具体的产品。
代码
这里我用构建房子作为案例
House --> Product

/** * @author zwf_xiaozhang * @describe 房子 */ public class House { /** * 地基 */ private String foundation; /** * 水泥 */ private String cement; /** * 电路 */ private String circuit; /** * 装修 */ private String renovation; public String getFoundation() { return foundation; }public void setFoundation(String foundation) { this.foundation = foundation; }public String getCement() { return cement; }public void setCement(String cement) { this.cement = cement; }public String getCircuit() { return circuit; }public void setCircuit(String circuit) { this.circuit = circuit; }public String getRenovation() { return renovation; }public void setRenovation(String renovation) { this.renovation = renovation; }@Override public String toString() { return "House{" + "foundation='" + foundation + '\'' + ", cement='" + cement + '\'' + ", circuit='" + circuit + '\'' + ", renovation='" + renovation + '\'' + '}'; } }

HouseBuilder -->Builder
/** * 抽象的 房屋建造者 */ public abstract class HouseBuilder { /** * 构建地基 */ abstract void buildFoundation(); /** * 构建钢筋水泥 */ abstract void buildCement(); /** * 构建电路 */ abstract void buildCircuit(); /** * 构建装修 */ abstract void buildRenovation(); /** * 构建完成 * @return 房子 */ abstract House getHouse(); }

HouseWorker --> Worker
/** * @author zwf_xiaozhang * @describe 房屋建造工作者 */ public class HouseWorker extends HouseBuilder{ /** * 未建造的房子 */ private House house; public HouseWorker() { this.house = new House(); }@Override void buildFoundation() { house.setFoundation("地基"); System.out.println("地基构建完成"); }@Override void buildCement() { house.setCement("水泥工程"); System.out.println("水泥工程构建完成"); }@Override void buildCircuit() { house.setCircuit("电路"); System.out.println("电路构建完成"); }@Override void buildRenovation() { house.setRenovation("装修"); System.out.println("装修完成"); }@Override House getHouse() { return house; } }

Director
/** * @author zwf_xiaozhang * @describe 指挥者 */ public class Director { /** * 指挥者指挥工作者按顺序构建房子 * @param houseBuilder 被指挥房屋构建者 *注意:Worker extends Builder 这里接收具体的woker就做具体的建造 * @return 构建好的房屋 */ public House build(HouseBuilder houseBuilder){ houseBuilder.buildFoundation(); houseBuilder.buildCement(); houseBuilder.buildCircuit(); houseBuilder.buildRenovation(); return houseBuilder.getHouse(); } }

Test 测试
package com.zwf.builder; public class Test { public static void main(String[] args) { //创建指挥者 Director director = new Director(); //指挥房子工作者构建房子 House house = director.build(new HouseWorker()); System.out.println(house); } }

打印结果:
设计模式|Builder建造者模式
文章图片

再看到定义,将一个复杂对象的构造与它的表示分离,使得同样的构造过程可以创建不同的表示。
复杂对象的表示就时我们测试中的代码,构造则是指挥者的build方法。build的入参可以传入不同的Worker来创造不同的产品,这里也就是使得同样的构造过程可以创建不同的表示。
标黄的这句话是不是有点继承特性那味了,构造居民房、商用房..等各种房子都由同意的构造过程,我们就可以定义一个抽象的Builder了,然后再由各自的Worker继承Builder,然后实现各自的建造细节!
指挥者接收不同的Worker就可以创建不同的表示了!
这里的指挥者按照构建房子的顺序来构建我们的房子,我们定于Builder来作为我们的入参,我们需要其他的工作者来构建对应的产品也算可以的。我们可以利用java继承的特性来灵活定义我们的构建者和工作者们的关系,然后再详细的定义我们的指挥者!

这是建造者模式的标准模型,我们可以自由发挥!
二、更灵活的建造者模式
  • 上面的builder模式的常规用法,指挥类Director再Builder模式中具有重要作用,它用于指导具体构建者如何构建产品,控制调用先后次序,并向调用者返回完整产品类,但是有些情况下需要简化系统结构,可以把Director和抽象建造者结合!
  • 通过静态内部类方式实现零件无需装配构造,这种方式使用更加灵活,更符合定义。内部有复杂对象的默认实现,使用时可以更具用户需求自由定义更改内容,并且无需改变具体的勾走方式。就可以生产出不同复杂产品。
下面我以麦当劳点套餐为例子:
注意:
我这个案例中的套餐,我是按照套餐的栏位来划分的。比如A套餐只有3个食品,那么A套餐就是三个栏位,B套餐4个食品就对应四个栏位。请根据自己的系统的业务来进行我们的建造者设计。
Product --> 套餐
该套餐拥有4个栏位,可以由用户自己指定对应栏位的食品!我们还可以对用户对每个栏位的食品选择进行限制,比如栏位1只能选汉堡类,比如鸡肉汉堡,牛肉汉堡...等
这些都需要我们根据系统需求进行设计!我这里的代码是我自己想象的一个业务,按照栏位任意选择了!主要还是为了演示更灵活的建造者模式!
package com.zwf.builder.demo2; /** * 四个栏位的套餐 * @author zwf_xiaozhang */ public class Product { /** * 默认的套餐搭配 */ private String one = "汉堡"; private String two = "可乐"; private String three = "薯条"; private String four = "鸡翅"; public String getOne() { return one; }public void setOne(String one) { this.one = one; }public String getTwo() { return two; }public void setTwo(String two) { this.two = two; }public String getThree() { return three; }public void setThree(String three) { this.three = three; }public String getFour() { return four; }public void setFour(String four) { this.four = four; }@Override public String toString() { return "Product{" + "one='" + one + '\'' + ", two='" + two + '\'' + ", three='" + three + '\'' + ", four='" + four + '\'' + '}'; } }

Builder --> 建造者
package com.zwf.builder.demo2; /** * 套餐建造者 * @author zwf_xiaozhang */ public abstract class Builder { /** * 构建栏位1的食品 */ abstract Builder builderOne(String foodName); /** * 构建栏位2的食品 */ abstract Builder builderTwo(String foodName); /** * 构建栏位3的食品 */ abstract Builder builderThree(String foodName); /** * 构建栏位4的食品 */ abstract Builder builderFour(String foodName); /** * 获取最终构建好的食品 * @return */ abstract Product getProduct(); }

Worker --> 工作者
package com.zwf.builder.demo2; public class Worker extends Builder{private Product product; public Worker() { product = new Product(); }/** * 工作者为用户制作栏位1用户所指定的食品 * @param foodName 用户指定的食品 */ @Override Worker builderOne(String foodName) { product.setOne(foodName); System.out.println("用户自选了食品:"+foodName); return this; }/** * 工作者为用户制作栏位2用户所指定的食品 * @param foodName 用户指定的食品 */ @Override Worker builderTwo(String foodName) { product.setTwo(foodName); System.out.println("用户自选了食品:"+foodName); return this; }/** * 工作者为用户制作栏位3用户所指定的食品 * @param foodName 用户指定的食品 */ @Override Worker builderThree(String foodName) { product.setThree(foodName); System.out.println("用户自选了食品:"+foodName); return this; }/** * 工作者为用户制作栏位4用户所指定的食品 * @param foodName 用户指定的食品 */ @Override Worker builderFour(String foodName) { product.setFour(foodName); System.out.println("用户自选了食品:"+foodName); return this; }/** * 获取最终的套餐 * @return */ @Override Product getProduct() { return product; } }

Test --> 测试
package com.zwf.builder.demo2; public class Test { public static void main(String[] args) { //创建工作者:该工作者是负责4个栏位套餐制作的工作者 Worker worker = new Worker(); //用户自选了栏位1、2的食品。3、4栏位为该套餐默认的食品 Product product = worker.builderOne("鸡肉汉堡").builderTwo("雪碧").getProduct(); //打印查看套餐结果 System.out.println(product); } }

从这个测试我们可以看到和第一个案例代码演示的不同了,可以直接一行代码完成所有需要的构建!Worker中的构建方法返回this就可以实现这样的操作!
打印结果如下:
设计模式|Builder建造者模式
文章图片

这个案例代码没有领导者,我们可以更具需要构建的成分更灵活的去创建。领导者更像是一个定义,用户可以从领导者那里调用定义好的各种套餐。去掉领导者就可以自己直接选择食品!






【设计模式|Builder建造者模式】

    推荐阅读