• 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、建造者模式中客户端可以控制如何构造对象的组件;工厂模式中客户端无法控制构建对象的细节;

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

  • 相关阅读:
    Using Repository and Unit of Work patterns with Entity Framework 4.0
    Accessing Your Model's Data from a Controller
    ASP.NET MVC 3 Internationalization
    Test your ASP.NET MVC or WebForms Application on IIS 7 in 30 seconds
    定时执行Web测试
    对包含HttpContext.Current.Cache的代码进行单元测试
    ASP.NET MVC判断基于Cookie的Session过期
    Selenium testing Iframe
    [Tips]: ASP.NET MVC得到controller的名字
    [Tips]:"RemoteOperationException: ERROR: wrong password for user" with Oracle 10g
  • 原文地址:https://www.cnblogs.com/jackion5/p/14334027.html
Copyright © 2020-2023  润新知