重学设计模式(三、设计模式-建造者模式)

101 阅读4分钟

1、建造者模式

​ 在前面我们讲到工厂模式,工厂模式的重点是封装了对象的创建,用户需要什么对象(产品),就给用户创建什么对象(产品),并不关心产品的组装顺序。比如我们在抽象工厂模式中的:要构建高端比亚迪,就获取高端比亚迪工厂;要构建低端比亚迪,就获取低端比亚迪工厂。那有一天客户需要中等比亚迪呢?

​ 中等比亚迪型号1(高端发动机、低端座椅、低端轮胎);

​ 中等比亚迪型号2(高端发动机、高端座椅、低端轮胎);

​ 中等比亚迪型号3(低端发动机、高端座椅、高端轮胎);

​ ....

​ 客户的需求是多变的,如果要为每种型号都提供一个工厂,那工厂太多了。这个时候我们就可以通过建造者模式根据用户的选择来定制产品。

1.1、什么是建造者模式

  • 定义:是一种创建型模式,可让您逐步构建复杂的对象。将一个复杂的对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。

​ 什么意思呢?我们先来看下实现建造者模式的一个结构。建造者(Builder)模式由抽象建造者、具体建造者、

产品、导向器等 4 个要素构成

​ 一般端直接和Director导向器沟通,通过向Director传入不同的ConcreteBuilder(具体建造者)构建不同表示的Product(产品)。

​ 所以建造者模式把对象的构建(由Builder的实现来负责的)和装配(由Director负责的)进行了解耦,不同的构建器,相同的装配,也可以做出不同的产品。

1.2、模式的优缺点

  • 优点

​ 1)可以逐步构建对象、延迟构建步骤,将构建和表示分离;

​ 2)各个具体的建造者相互独立,您可以重用相同的构建代码;

  • 缺点

​ 产品的组成部分必须相同,这限制了其使用范围,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。

1.3、创建的方式

​ 首先创建抽象建造者;

//1)抽象建造者
public interface Builder {
 void setTyre(Tyre tyre);
 void setSeat(Seat seat);
 void setEngine(Engine engine);
}

class Tyre{
 private String tyreVersion;

 public Tyre(){
  this.tyreVersion="入门级轮胎,寿命5年";
 }
 public Tyre(String tyreVersion) {
  this.tyreVersion = tyreVersion;
 }

 public String getTyreVersion() {
  return tyreVersion;
 }
}

class Seat{
 private String SeatVersion;

 public Seat(){
  this.SeatVersion="普通座椅";
 }
 
 public Seat(String seatVersion) {
  SeatVersion = seatVersion;
 }
 
 public String getSeatVersion() {
  return SeatVersion;
 }

}

class Engine{
 private String EngineVersion;

 public Engine(){
  this.EngineVersion="普通发动机";
 }
 
 public Engine(String engineVersion) {
  EngineVersion = engineVersion;
 }
 public String getEngineVersion() {
  return EngineVersion;
 }
}

​ 然后再创建实际建造者及产品;

//2)实际建造者
public class BydBuilder implements Builder {

 private Tyre tyre;
 private Seat seat;
 private Engine engine;
 
 @Override
 public void setEngine(Engine engine) {
  this.engine = engine;
 }

 @Override
 public void setSeat(Seat seat) {
        this.seat = seat; 
 }

 @Override
 public void setTyre(Tyre tyre) {
        this.tyre = tyre;
 }
    //得到产品
 public BydCar getMyBydCar(){
  return new BydCar(tyre, seat, engine);
 }
}

class BydCar{
 private Tyre tyre;
 private Seat seat;
 private Engine engine;
 
 public BydCar(Tyre tyre,Seat seat,Engine engine){
  this.tyre = tyre;
  this.seat = seat;
  this.engine = engine;
  System.out.println(this.toString());
 }
 
 public Tyre getTyre() {
  return tyre;
 }
 public Seat getSeat() {
  return seat;
 }
 public Engine getEngine() {
  return engine;
 }

 @Override
 public String toString() {
  return this.engine.getEngineVersion()+"+"+
         this.tyre.getTyreVersion()+"+"+
         this.seat.getSeatVersion();
 }
 
}

​ 再创建导向器

//3)创建导向器
public class Director {

 public void highBydCar(Builder builder){
  builder.setEngine(new Engine("高端发动机"));
  builder.setTyre(new Tyre("高端轮胎,可用10年"));
  builder.setSeat(new Seat("高端真皮座椅"));
 }
 
 public void lowBydCar(Builder builder){
  builder.setEngine(new Engine());
  builder.setTyre(new Tyre());
  builder.setSeat(new Seat());
 }
 //目前预售中端款比亚迪
 public void MiddleBydCar(Builder builder){
  builder.setEngine(new Engine("高端发动机"));
  builder.setTyre(new Tyre()); //低端轮胎
  builder.setSeat(new Seat()); //低端座椅
 }
}

​ 最后就是我们的客户端调用者。

public class Client {

 public static void main(String[] args) {
   //导向器
   Director director = new Director();
   //建造者
   BydBuilder builder = new BydBuilder();
   //产品
   System.out.println("顾客1,看中了高端比亚迪");
   director.highBydCar(builder);
   builder.getMyBydCar();
   System.out.println("顾客2,看中了低端比亚迪");
   director.lowBydCar(builder);
   builder.getMyBydCar();
   System.out.println("顾客3,看中了中端比亚迪");
   director.MiddleBydCar(builder);
   builder.getMyBydCar();
   
   System.out.println("顾客4,希望按照自己的意愿定制比亚迪");
   builder.setEngine(new Engine("高端发动机"));
   builder.setSeat(new Seat("高端座椅"));
   builder.setTyre(new Tyre());//低端轮胎
   builder.getMyBydCar();
 }
}

​ 案例执行效果:

案例中不仅仅有导向器中提供给使用者的一些产品,还支持使用者定制自己的产品。

1.4、总结及建议

​ 建造者模式实现了构建和装配的解耦,不同的构建器,相同的装配,可以做出不同的产品对象;相同的构建器不同的装配顺序也可以做出不同的产品对象。

应用场景:

  • 相同的方法,不同的执行顺序,产生不同的结果。
  • 产品类非常复杂,或者产品类中不同的调用顺序产生不同的作用。
  • 初始化一个对象特别复杂,参数多,而且很多参数都具有默认值。

DJK中建造者模式的使用:

  • java.lang.StringBuilder#append() (unsynchronized)
  • java.lang.StringBuffer#append() (synchronized)
  • java.nio.ByteBuffer#put()
  • javax.swing.GroupLayout.Group#addComponent()