美文网首页
java设计模式(三)建造者模式

java设计模式(三)建造者模式

作者: IT废柴 | 来源:发表于2017-12-19 08:59 被阅读0次

    开篇废话

    周末因懒的原因,停更了两天。今天主要研究建造者模式。畅游各大博客网站,推荐一篇关于建造者模式的博客http://blog.csdn.net/self_study/article/details/51707029,简单明了,条例清晰。如果看不懂我写的,可以尝试去看看别人的。。。

    什么是建造者模式

    讲建造者模式,这里要提取几个关键词:

    • 复杂对象: 这里简单的体现可以理解为,这里对象的成员数量很多,所以它很复杂。
    • 构建过程: 对成员对象进行赋值,业务逻辑生成等一系列使之成为一个成熟的对象。
    • 表示: 返回这个对象。
    • 构建过程与表示分离: 一般来说,对成员对象的赋值通常在构造函数中,这种方式除了不够灵活之外,还有就是如果成员对象过多,因为构造函数就会显得十分臃肿。所以,我们可以将构建过程(简单的理解为赋值,这里不严谨,只是为了帮助理解概念)封装成独立的方法,然后再返回整个需要的实例对象。

    那么建造者模式:就是为了解决生成复杂对象的问题,主要通过将构建过程与表示分离的方法。


    如何实现建造者模式

    理解了建造者模式后,我们来实现它,就相对简单了。
    首先盗图一张:


    建造者模式类图

    可以看到,这里呈现了四个类,有时候实际开发中会将这个模型进行简化,我们这里先学习理论,因为实际操作时,灵活变动太多了,不适合讲解。但是万变不离其宗,核心思想就是这些。

    • Product,都称这个为产品类,说白了就是我需要生成的类。
    • Builder类,这是一个抽象类或者接口,用来规定构建对象的所需方法。
    • ConcreteBuilder 对builder的抽象方法的实现类,通常对其优化为product的内部类,从而省掉builder的定义。常见的有 AlertDialog.Builder 。
    • Director 调用concrete的方法的类。一般来说,使用的建造者模式时,这个也给省了。

    我们先来看一个完整版的。以造汽车为例,现在我们需要一辆,有四个轮子,有四个座椅,有防风玻璃,有方向盘,发动机等等(这里只列举这几样)。

    • 首先我们先看Product类,就是我们要生成的复杂对象,这里就是指小汽车。
    public class Car {
        List<String> tyres = new ArrayList<>();
        List<String> carMounts = new ArrayList<>();
        String glass;
        String steeringWheel;
        String engine;
    
        public void setTyres(String tyres) {
            this.tyres.add(tyres);
        }
    
        public void setCarMounts(String carMounts) {
            this.carMounts.add(carMounts);
        }
    
        public void setGlass(String glass) {
            this.glass = glass;
        }
    
        public void setSteeringWheel(String steeringWheel) {
            this.steeringWheel = steeringWheel;
        }
    
        public void setEngine(String engine) {
            this.engine = engine;
        }
    
        public List<String> getTyres() {
            return tyres;
        }
    
        public List<String> getCarMounts() {
            return carMounts;
        }
    
        public String getGlass() {
            return glass;
        }
    
        public String getSteeringWheel() {
            return steeringWheel;
        }
    
        public String getEngine() {
            return engine;
        }
    
    }
    

    这里可以看到小汽车有五个属性,然后通过setter和getter方法来对属性赋值。

    • 然后我们先看Builder类,这是一个抽象类或者接口,具体使用看情况而定,我今天想用接口表示:
    public interface Builder {
        public void buildeTyre(int wheelNumber);
        public void buildCarMounts(int carMountsNumber);
        public void buildGalss();
        public void buildSteeringWheel();
        public void buildEngine();
        public Car build();
    }
    

    这里定义了五个造小汽车零件的方法,和一个生成对象方法,因为你不能只造这些零件,还需要把这些零件给组装起来啊。

    • 紧接着我们需要ConcreteBuilder类来实现这些方法啊,毕竟我们是实干家,不能光说不做!concretebuilder
    public class CarBuilder implements Builder {
        
        Car car = new  Car();
        @Override
        public void buildeTyre(int wheelNumber) {
            for (int i = 0; i < wheelNumber; i++) {
                car.setTyres("已经造了" + i + "轮子了");
            }
        }
    
        @Override
        public void buildCarMounts(int carMountsNumber) {
            for (int i = 0; i < carMountsNumber; i++) {
                car.setCarMounts("已经造了" + i + "椅子了");
            }
        }
    
        @Override
        public void buildGalss() {
            car.setGlass("防风玻璃做好了");
        }
    
        @Override
        public void buildSteeringWheel() {
            car.setSteeringWheel("方向盘做好了");
        }
    
        @Override
        public void buildEngine() {
            car.setEngine("发动机已经做好了");
        }
    
        @Override
        public Car build() {
            return car;
        }
    
    }
    

    这里实现了builder接口,没什么好说的,值得注意的就是,在CarBuilder类中,维护了一个Car对象,实现的所有方法中,去调用Car的set方法,最后build()方法中去返回这个对象。
    此时此刻,我们已经能通过CarBuilder类去建造我们所需要的Car对象了。但是毕竟造汽车的工序是及其复杂了,因为我们这里只简单的列举了五项,可能感觉还是比较轻松的,但是,如果有上百道工序的话,难道我们需要每次去造小车的时候都去调用这上百个方法吗。显然,这里构建的过程,我们希望是不透明的,那么我们可以将这个步骤封装起来,于是就有了Director类的出现。

    • 我们希望有一个技术总工来调度负责整个造车的过程。
    public class AodiDirecter {
        private Builder builder;
    
        public AodiDirecter(Builder builder) {
            this.builder = builder;
        }
    
        public void construct() {
            builder.buildeTyre(4);
            builder.buildCarMounts(4);
            builder.buildEngine();
            builder.buildGalss();
            builder.buildSteeringWheel();
        }
    }
    

    这样整个建造者模式就完成了,而我们需要一个奥迪车时,只需要:

    public class Buyer {
        public void buy() {
            Builder builder = new CarBuilder();
            AodiDirecter director = new AodiDirecter(builder);
            director.construct();
            Car aodiCar = builder.build();
        }
    }
    

    如果说,builder是产线工人们,AodiDirecter 就可以理解为奥迪工程师,工人们只知道制造器件,工程师来统筹设计造车的工序,安排下去后,工人们按命令执行就行了。而对于买家来说,我并看不到你是怎么造的,反正我只要结果就行了。


    但是这样往往会很麻烦,我们通常会对其进行精简优化。

    看上面对建造者定义了四个功能模块,在实现过程中,是不是有一些,何必多此一举的感觉。这里我盗用了别人的代码,工作繁忙(太懒了)还请谅解。

    public class Computer {
        private String CPU;
        private String GPU;
        private String memoryType;
        private int memorySize;
        private String storageType;
        private int storageSize;
        private String screenType;
        private float screenSize;
        private String OSType;
    
        public static class Builder {
            // Optional parameters - initialize with default values
            private String CPU = "inter-i3";
            private String GPU = "GTX-960";
            private String memoryType = "ddr3 1666MHz";
            private int memorySize = 8;//8GB
            private String storageType = "hdd";
            private int storageSize = 1024;//1TB
            private String screenType = "IPS";
            private float screenSize = 23.8f;
            private String OSType = "Windows 10";
    
            public Builder() {
            }
    
            public Builder setCPU(String CPU) {
                this.CPU = CPU;
                return this;
            }
    
            public Builder setGPU(String GPU) {
                this.GPU = GPU;
                return this;
            }
            public Builder setMemoryType(String memoryType) {
                this.memoryType = memoryType;
                return this;
            }
    
            public Builder setMemorySize(int memorySize) {
                this.memorySize = memorySize;
                return this;
            }
            public Builder setStorageType(String storageType) {
                this.storageType = storageType;
                return this;
            }
    
            public Builder setStorageSize(int storageSize) {
                this.storageSize = storageSize;
                return this;
            }
    
            public Builder setScreenType(String screenType) {
                this.screenType = screenType;
                return this;
            }
            public Builder setScreenSize(float screenSize) {
                this.screenSize = screenSize;
                return this;
            }
    
            public Builder setOSType(String OSType) {
                this.OSType = OSType;
                return this;
            }
    
    
            public Computer create() {
                return new Computer(this);
            }
    
        }
    
        private Computer(Builder builder) {
            CPU = builder.CPU;
            GPU = builder.GPU;
            memoryType = builder.memoryType;
            memorySize = builder.memorySize;
            storageType = builder.storageType;
            storageSize = builder.storageSize;
            screenType = builder.screenType;
            screenSize = builder.screenSize;
            OSType = builder.OSType;
        }
    }
    

    可以看到,整个建造者模式就是一个类,然而这个类中存在一个静态内部类Builder,这个Builder,其实对应的是建造者模式中的concreteBuilder,Computer对应的就是我们product。去掉了Builder抽象类,因为直接实现了。同时还缺少了Directer,因为这里的设计是暴露构建细节,所以就不需要了。
    这种方式的好处就是,过程可控。我们来看看调用。

    Computer computer = new Computer.Builder()
            .setCPU("inter-skylake-i7")
            .setGPU("GTX-Titan")
            .setMemoryType("ddr4-2133MHz")
            .setMemorySize(16)
            .setStorageType("ssd")
            .setStorageSize(512)
            .setScreenType("IPS")
            .setScreenSize(28)
            .setOSType("Ubuntu/Window10")
            .create();
    

    这是一种链式调用,也是我们常见的建造者模式。我们可以对每个成员对象进行控制,从而得到我们想要的product。当然,我们看回Computer类的实现,发现,每个成员对象都是有个默认值的。也就是说,你完全可以通过new Computer.Builder().create()来获取默认的实例对象,这基本就是Directer的功能。所以精简下来,发现建造者模式还是挺实用的。
    然而在大型的系统中,精简版的建造者模式,并不是很适用,因为它的针对性太强,往往呈现出来的是同一种产品,拓展性并不是很好,而我们使用原始版的话,可以对Directer进行拓展,可以更加多元灵活。

    相关文章

      网友评论

          本文标题:java设计模式(三)建造者模式

          本文链接:https://www.haomeiwen.com/subject/hkvpwxtx.html