JAVA常用设计模式3--建造者模式

一、建造者模式简介

1.1、定义

建造者模式指将一个复杂的对象构造过程和对象的表示进行分离。使同样的建造过程可以创建不同的表示,将构建过程拆分成多个简单的对象,将不变和变进行分离。不变的是对象的组成部分,变化的是每个部分的具体内容。

比如建造汽车的过程,不变的是都需要车身、底盘、车轮、发动机等组件,变化的是每个组件可以有不同的构造过程。

1.2、优缺点

a.封装性好,构建和表示进行分离

b.扩展性好,各个具体的建造者相互独立,各个组件之间互相解耦

c.对象调用者无需关系对象的具体建造过程,满足迪米特法则

1.3、建造者模式的角色

产品:需要建造的对象,通常包含是由多个简单的组件组合成的复杂对象

抽象建造者:包含创建产品各个子部件的抽象方法的接口,通过还包含一个返回复杂对象的方法用于返回建造后的对象

具体建造者:实现抽象建造者,完成复杂产品各个子部件的具体创建

指挥者:调用建造者对象中的部件构造方法与装配方法完成复杂对象的创建,指挥者不关心具体产品的信息

二、建造者模式案例

1、业务场景

构造一个汽车对象,汽车对象包含了车身、底盘、发动机、车轮等核心组件

2、代码实现

a.定义汽车对象及各个组件的实体类

 1 /**
 2  * 汽车类
 3  */
 4 public class Car {
 5 
 6     //车架
 7     private CarFrame frame;
 8 
 9     //发动机
10     private Engine engine;
11 
12     //底盘
13     private Chassis chassis;
14 
15     //车轮
16     private Wheel wheel;
17 
18     public CarFrame getFrame() {
19         return frame;
20     }
21 
22     public void setFrame(CarFrame frame) {
23         this.frame = frame;
24     }
25 
26     public Engine getEngine() {
27         return engine;
28     }
29 
30     public void setEngine(Engine engine) {
31         this.engine = engine;
32     }
33 
34     public Chassis getChassis() {
35         return chassis;
36     }
37 
38     public void setChassis(Chassis chassis) {
39         this.chassis = chassis;
40     }
41 
42     public Wheel getWheel() {
43         return wheel;
44     }
45 
46     public void setWheel(Wheel wheel) {
47         this.wheel = wheel;
48     }
49 }

b.定义抽象建造者,提供返回对象的方法并定义汽车对象构建各个子部件的抽象

 1 /**
 2  * 抽象汽车建造者
 3  */
 4 public abstract class CarBuilder {
 5 
 6     protected Car car = new Car();
 7 
 8     /** 返回构造的汽车对象*/
 9     public Car builder(){
10         return car;
11     }
12 
13     /** 构建车架*/
14     public abstract CarBuilder frame();
15 
16     /** 构建发动机*/
17     public abstract CarBuilder engine();
18 
19     /** 构建底盘*/
20     public abstract CarBuilder chassis();
21 
22     /** 构建车轮*/
23     public abstract CarBuilder wheel();
24 }

c.实现具体的建造者,如奔驰汽车建造者

 1 /**
 2  * 奔驰汽车建造者实现类
 3  */
 4 public class BenzCarBuilder extends CarBuilder{
 5 
 6     @Override
 7     public CarBuilder frame() {
 8         System.out.println("奔驰建造者构建车轮");
 9         car.setFrame(new CarFrame("奔驰车轮"));
10         return this;
11     }
12 
13     @Override
14     public CarBuilder engine() {
15         System.out.println("奔驰建造者构建发动机");
16         car.setEngine(new Engine("奔驰发动机"));
17         return this;
18     }
19 
20     @Override
21     public CarBuilder chassis() {
22         System.out.println("奔驰建造者构建底盘");
23         car.setChassis(new Chassis("奔驰底盘"));
24         return this; this;
25     }
26 
27     @Override
28     public CarBuilder wheel() {
29         System.out.println("奔驰建造者构建车轮");
30         car.setWheel(new Wheel("奔驰车轮"));
31         return this;
32     }
33 }

测试代码如下:

1 public static void main(String[] args){
2         CarBuilder builder = new BenzCarBuilder();
3         /** 通过奔驰建造者构建汽车对象 */
4         Car car = builder.frame().engine().chassis().builder();
5         System.out.println(JSON.toJSONString(car));
6     }
1 奔驰建造者构建车轮
2 奔驰建造者构建发动机
3 奔驰建造者构建底盘
4 {"chassis":{"name":"奔驰底盘"},"engine":{"name":"奔驰发动机"},"frame":{"name":"奔驰车轮"}}

调用方main函数中无需关心汽车是如何构建的,只需要关心需要将哪些组件组合到汽车对象上。如果汽车需要增加或者删除一些组件,只需要在抽象建造者中增加或删除对应的方法即可,比如需要添加仪表盘组件,则只需要定义仪表盘对象,并且在抽象建造者中添加对应的方法即可,代码如下:

定义仪表盘类DashBoard类,并在Car中添加属性,修改抽象建造者类,添加构造仪表盘的方法

 1 /**
 2  * 抽象汽车建造者
 3  */
 4 public abstract class CarBuilder {
 5 
 6     protected Car car = new Car();
 7 
 8     /** 返回构造的汽车对象*/
 9     public Car builder(){
10         return car;
11     }
12 
13     /** 构建车架*/
14     public abstract CarBuilder frame();
15 
16     /** 构建发动机*/
17     public abstract CarBuilder engine();
18 
19     /** 构建底盘*/
20     public abstract CarBuilder chassis();
21 
22     /** 构建车轮*/
23     public abstract CarBuilder wheel();
24 
25     /** 构建仪表盘*/
26     public abstract CarBuilder bashBoard();
27 }

此时构造汽车时就可以加上仪表盘的构造

1 public static void main(String[] args){
2         CarBuilder builder = new BenzCarBuilder();
3         /** 通过奔驰建造者构建汽车对象 */
4         Car car = builder.frame().engine().chassis().bashBoard().builder();
5         System.out.println(JSON.toJSONString(car));
6     }

另外本例子中的具体建造者是直接实现了构建细节,还可以改造成将构建细节分离,将构建的组件进行抽象化,比如将上例中的需求改动,汽车不再由奔驰建造者来建造,而是由一个第三方建造者来构建,第三方建造者造汽车时可能会用保时捷的发动机、奔驰的车身、宝马的底盘和奥迪的仪表盘,此时将构建细节交给具体建造者的化就不好扩展,所以具体建造者应该将构建组件的部分抽象分离出去。代码如下:

将各个组件抽象化

/**
 * 车架组件
 */
public interface CarFrame {
    public String name();
}
/**
 * 底盘组件
 */
public interface Chassis {
    public String name();
}
/**
 * 发动机组件
 */
public interface Engine {
    public String name();
}
/**
 * 车轮组件
 */
public interface Wheel {
    public String name();
}
/**
 * 仪表盘抽象
 */
public interface BashBoard {
    public String name();
}

修改抽象建造者类,此时由于组件是直接由外部构建,那么可以直接去除建造者类的抽象定义,直接由建造者类构建即可,代码如下:

 1 /**
 2  * 抽象汽车建造者
 3  */
 4 public class CarBuilder {
 5 
 6     protected Car car = new Car();
 7 
 8     /** 返回构造的汽车对象*/
 9     public Car builder(){
10         return car;
11     }
12 
13     /** 构建车架*/
14     public  CarBuilder frame(CarFrame carFrame){
15         car.setFrame(carFrame);
16         return this;
17     }
18 
19     /** 构建发动机*/
20     public  CarBuilder engine(Engine engine){
21         car.setEngine(engine);
22         return this;
23     }
24 
25     /** 构建底盘*/
26     public  CarBuilder chassis(Chassis chassis){
27         car.setChassis(chassis);
28         return this;
29     }
30 
31     /** 构建车轮*/
32     public  CarBuilder wheel(Wheel wheel){
33         car.setWheel(wheel);
34         return this;
35     }
36 
37     /** 构建仪表盘*/
38     public  CarBuilder bashBoard(BashBoard bashBorad){
39         car.setBashBoard(bashBorad);
40         return this;
41     }
42 }

测试代码如下:

 1 public static void main(String[] args){
 2         CarBuilder builder = new CarBuilder();
 3         /** 通过建造者类构建汽车对象 */
 4         Car car = builder
 5                 .frame(new BenzFrame())//奔驰车架
 6                 .engine(new PorscheEngine())//保时捷发动机
 7                 .chassis(new BmwChassis())//宝马底盘
 8                 .bashBoard(new AudiBashBoard())//奥迪仪表盘
 9                 .wheel(new MichelinWheel())//米其林车轮
10                 .builder();
11         System.out.println(car.toString());
12     }
1 {"engine":"保时捷发动机","wheel":"米其林车轮","chassis":"宝马底盘","bashBoard":"奥迪仪表盘","frame":"奔驰车架"}

两种实现方式都各自有各自的优点,可以根据具体的业务场景选择更方便的更具有扩展性的方式来实现。

三、建造者模式和工厂模式的对比

1、建造者不关注组件的生产过程,只关心复杂对象的构建过程;而工厂模式需要关心各个组件的生产过程;

2、建造者倾向于建造结构相同内容不同的对象;工厂模式倾向于批量生产结构相同且内容也相同的对象;

3、建造者模式中客户端可以控制如何构造对象的组件;工厂模式中客户端无法控制构建对象的细节;

可以表示中建造者模式更加注重的是创建对象的过程;工厂模式更加注重的是创建对象的结果。

原文地址:https://www.cnblogs.com/jackion5/p/14334027.html