zoukankan      html  css  js  c++  java
  • Java设计模式之(三)——建造者模式

    1、什么是建造者模式

    Separate the construction of a complex object from its representation so that the same construction process can create different representations.

    将一个复杂对象的构建与它的表示分离, 使得同样的构建过程可以创建不同的表示。

    说人话:将构造复杂对象的过程和组成对象的部件解耦。就像攒电脑一样,不管什么品牌的配件,只要兼
    容就可以装上;同样,一样的配件,可以有好多组装的方式。更直接点就是同一个类,通过内部不同属性状态构造不同的对象。

    2、建造者模式定义

    image-20210831081701593

    在建造者模式中,有 4 个定义:

    ①、Product(产品类) :我们具体需要生成的类对象

    ②、Builder(抽象建造者类):为我们需要生成的类对象,构建不同的模块属性,即:公开构建产品类的属性,隐藏产品类的其他功能。

    ③、ConcreteBuilder(具体建造者类):实现抽象类定义的所有方法,并返回一个组建好的对象。

    ④、Director(导演类):确定构建我们的类对象具体有哪些模块属性,在实际应用中可以不需要这个角色,直接通过client处理。

    3、实例

    比如我们去买车,一般同一辆车会有多个版本,根据配置不一样,分为经典版、舒适版、豪华版等,比如经典版是手动挡手动座椅,舒适版是自动挡全景天窗等。

    public class Car {
        // 车名称
        private String name;
        // 自动挡
        private String automaticCatch;
        // 手动挡
        private String manualTransmission;
        // 全景天窗
        private String panoramicSunroof;
        // 自动座椅
        private String automaticSeat;
        // 手动座椅
        private String manualSeat;
        // 倒车影像
        private String reversingImage;
    
        //省略get/set方法
    }
    

    3.1 普通实现

    public class GeneralTest {
        public Car getCarInstance(String carName){
            Car car = new Car();
            if("经典版".equals(carName)){
                car.setName("经典版");
                car.setManualTransmission("手动挡");
            }else if("舒适版".equals(carName)){
                car.setName("舒适版");
                car.setAutomaticCatch("自动挡");
                car.setManualSeat("手动座椅");
            }else if("豪华版".equals(carName)){
                car.setName("豪华版");
                car.setAutomaticCatch("自动挡");
                car.setAutomaticSeat("自动座椅");
                car.setReversingImage("倒车影像");
                car.setPanoramicSunroof("全景天窗");
            }else{
                throw new IllegalArgumentException("carName is error: carName="+carName);
            }
            return car;
        }
    }
    

    注意,并不是说高版本汽车一定具有低版本所有配置,比如舒适版配置是手动座椅,豪华版是自动座椅,而且不同版本之间配置有交叉。

    从上面可以看出,根据汽车类型,我们可以创建相应配置的汽车,但其实汽车的配置是有很多的,种类一旦多了,上面的代码就会显得很臃肿,也不好维护,于是我们用建造者模式来重构。

    3.2 建造者模式实现

    ①、创建抽象建造者类

    public abstract class CarBuilder {
    
        public abstract Car buildClassic();
    
        public abstract Car buildComfortable();
    
        public abstract Car buildLuxury();
    
    }
    

    ②、创建具体建造者类。对抽象建造者类的抽象方法进行实现赋值,达到我们所需要的结果。

    public class CarConcreteBuilder extends CarBuilder{
    
        @Override
        public Car buildClassic() {
            Car car = new Car();
            car.setName("经典版");
            car.setManualTransmission("手动挡");
            return car;
        }
    
        @Override
        public Car buildComfortable() {
            Car car = new Car();
            car.setName("舒适版");
            car.setAutomaticCatch("自动挡");
            car.setManualSeat("手动座椅");
            return car;
        }
    
        @Override
        public Car buildLuxury() {
            Car car = new Car();
            car.setName("豪华版");
            car.setAutomaticCatch("自动挡");
            car.setAutomaticSeat("自动座椅");
            car.setReversingImage("倒车影像");
            car.setPanoramicSunroof("全景天窗");
            return car;
        }
    }
    

    ③、创建我们的导演类,指导我们怎么去创建对象

    public class CarDirector {
        private CarBuilder carBuilder;
    
        public CarDirector(CarBuilder carBuilder){
            this.carBuilder = carBuilder;
        }
    
        public Car classicConstruct(){
            return carBuilder.buildClassic();
        }
    
        public Car comfortableConstruct(){
            return carBuilder.buildComfortable();
        }
    
        public Car luxuryConstruct(){
            return carBuilder.buildLuxury();
        }
    }
    

    ④、测试

    public class BuilderTest {
        public static void main(String[] args) {
            CarBuilder carBuilder = new CarConcreteBuilder();
            CarDirector carDirector = new CarDirector(carBuilder);
            Car classicCar = carDirector.classicConstruct();
            System.out.println(classicCar);
            Car comfortableCar = carDirector.comfortableConstruct();
            System.out.println(comfortableCar);
        }
    }
    

    另外,对于不同配置之间有互斥关系,比如有了手动挡,就不可能有自动挡,属性之间的关系我们也可以在具体建造者类 CarConcreteBuilder 进行设置。

    4、与工厂模式区别

    前面我们介绍工厂模式时说了由工厂类来负责创建对象,而建造者模式也是让具体建造者类负责创建对象,那这两者有什么区别呢?

    实际上工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。而建造者模式是用来创建一种类型的复杂对象,通过设置不同的可选参数,“定制化”地创建不同的对象。

    有这样一个例子可以形象的解释:

    顾客走进一家餐馆点餐,我们利用工厂模式,根据用户不同的选择,来制作不同的食物,比如披萨、汉堡、沙拉。对于披萨来说,用户又有各种配料可以定制,比如奶酪、西红柿、起司,我们通过建造者模式根据用户选择的不同配料来制作披萨。

    5、建造者模式优点

    ①、封装性

    使用建造者模式可以使客户端不必知道产品内部组成的细节, 如例子中我们就不需要关心每一种版本汽车内部是如何实现的, 产生的对象类型就是Car。

    ②、建造者独立,容易扩展

    其实对于上面例子中的 CarConcreteBuilder 类,有三个方法,分别构造经典版、舒适版、豪华版汽车,每个方法内部是不受影响的,或者我们还可以直接把这一个类拆成三个类。

    ③、便于控制细节风险

    由于具体每个建造者过程是独立的,因此可以对过程更加细化,而不会对其它模块产生影响。

    6、建造者模式使用场景

    ①、相同的方法, 不同的执行顺序, 产生不同的事件结果时, 可以采用建造者模式。

    ②、多个部件或零件, 都可以装配到一个对象中, 但是产生的运行结果又不相同时, 则可以使用该模式。

    ③、产品类非常复杂, 或者产品类中的调用顺序不同产生了不同的效能, 这个时候使用建造者模式非常合适。

    作者:IT可乐

    资源:微信搜【IT可乐】关注我,回复 【电子书】有我特别筛选的免费电子书。
    本文版权归作者所有,欢迎转载,但未经作者同意不能转载,否则保留追究法律责任的权利。
  • 相关阅读:
    JavaScript闭包
    模块模式——方法
    产品与技术
    读书笔记
    屌丝求职记
    正则表达式regex狂记
    css狂记
    html狂记
    Android狂记忆
    关于调式
  • 原文地址:https://www.cnblogs.com/ysocean/p/15575511.html
Copyright © 2011-2022 走看看