设计模式-建造者模式

建造者模式:把类对象的构造与装配分别实现。

单例、工厂、原型这几种模式的重点在于创建出一个个的实例对象来,而这个建造者模式的重点在于对某个对象的组成部分的装配。

在实际开发中,一个类不可能只有简单的几个属性,往往是有大量的属性。创建对象的同时或者之后,给属性也设置好对应的值,这个对象才有使用的价值。否则一个空对象我们用它做什么呢。

如果一个表有20个字段,那么它对应的实体类就有20个属性,如何给这个类的对象的属性赋值呢。要么是利用构造方法在创建对象的同时就赋值,要么就是创建一个空对象,然后用set方法给赋值。
构造器的方法问题就是不够灵活,而set方法就是代码量大。

建造者模式可以完美的解决这个问题。
先看一下建造者模式的一般方式:
这里有三个基本角色:产品(有比较多、复杂的组件),构造者,装配者
这里以电脑这种产品为例:

public class Computer {

    private String cpu;
    private String memery;
    private String screen;

    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", memery='" + memery + '\'' +
                ", screen='" + screen + '\'' +
                '}';
    }
    // 省略get与set方法
}

构造者,用来模拟构造产品的各个组成部分

// 抽象构造者
public abstract class Builder {
    Computer computer = new Computer();

    // 构建cpu
    protected abstract void buildCpu();

    // 构建memery
    protected abstract void buildMemery();

    // 构建screen
    protected abstract void buildScreen();

}
// 具体的建造者
public class HuaweiComputer extends Builder{
    @Override
    protected void buildCpu() {
        computer.setCpu("only amd ...");
    }

    @Override
    protected void buildMemery() {
        computer.setMemery("sangsam  1024G");
    }

    @Override
    protected void buildScreen() {
        computer.setScreen("huawei 27 big screen");
    }
}

public class AppleComputer extends Builder{
    @Override
    protected void buildCpu() {
        computer.setCpu("inter i7");
    }

    @Override
    protected void buildMemery() {
        computer.setMemery("kinston 256G");
    }

    @Override
    protected void buildScreen() {
        computer.setScreen("apple cloure");
    }
}

装配者,不同的产品只是组件不同,但是装配流程是相同的

public class Director {
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public Computer createComputer(){
        builder.buildCpu();
        builder.buildMemery();
        builder.buildScreen();
        return builder.computer;
    }
}

测试

public class ClientDemo {
    public static void main(String[] args) {
        // 通过给装配者传递不同的产品构造者来得到不同的产品
//        Director director = new Director(new AppleComputer());
        Director director = new Director(new HuaweiComputer());
        Computer computer = director.createComputer();
        System.out.println(computer);
    }
}

当然从这里我们可以看到这种模式的适用场景,那就是产品应当是同一类产品,产品的组成部分可能很多,各个组成部分可能不相同,但是他们组成这个产品的整理逻辑(装配流程)是相同的。

其实本质上还是封装,我们把不同的部分(组成部分)单独实现,相同的部分(装配)统一实现。

也可以把构造者和装配者这两个角色放在一起来实现,如下:

public abstract class BuilderTotal {
    Computer computer = new Computer();
    // 构造者:构造产品的各个组成部分
    protected abstract void buildCpu();
    protected abstract void buildMemry();
    protected abstract void buildScreen();
    // 装配者:完成组装
    public Computer createCoumputer(){
        this.buildCpu();
        this.buildMemry();
        this.buildScreen();
        return this.computer;
    }
}

不同的产品

public class XiaomiComputer extends BuilderTotal{
    @Override
    protected void buildCpu() {
        computer.setCpu("xiaomi  cpu");
    }

    @Override
    protected void buildMemry() {
        computer.setMemery("xiaomi  memery");
    }

    @Override
    protected void buildScreen() {
        computer.setScreen("xiaomi screen");
    }
}

public class HpComputer extends BuilderTotal{
    @Override
    protected void buildCpu() {
        computer.setCpu("hp special cpu");
    }

    @Override
    protected void buildMemry() {
        computer.setMemery("hp special memery");
    }

    @Override
    protected void buildScreen() {
        computer.setScreen("hp special screen");
    }
}

测试:

public class ClientDemo_02 {
    public static void main(String[] args) {
        BuilderTotal hp = new HpComputer();
        Computer coumputer = hp.createCoumputer();
        System.out.println(coumputer);
        System.out.println("========================");
        BuilderTotal xiaomi = new XiaomiComputer();
        Computer computer = xiaomi.createCoumputer();
        System.out.println(computer);
    }
}

虽然这样是把不同的功能放在同一个类中实现,不符合单一原则,但其实我觉得这样的代码可读性要高一点,不过当属性比较多的时候,也会比较乱。

接下来看一种比较巧妙的方式,利用内部类的方式,对产品的各个部分(属性)进行组装,而且非常灵活。

public class Phone {
    private String brand;
    private String memory;
    private String screen;
    private String camera;
    private String clour;

    // 私有构造方法,创建对象由内部类的方法实现(最后用到)
    private Phone(String brand, String memory, String screen, String camera, String clour) {
        this.brand = brand;
        this.memory = memory;
        this.screen = screen;
        this.camera = camera;
        this.clour = clour;
    }

    // 借助一个内部类,用来构造属性的各个部分,并创建调用它的构造方法创建对象返回给调用者
    public static PhoneBuilder phoneBuilder(){
        return new PhoneBuilder();
    }

    // 静态内部类实现
    public static class PhoneBuilder{
        // 拥有和外部类相同的参数
        private String brand;
        private String memory;
        private String screen;
        private String camera;
        private String clour;
        // 对每一个属性提供一个方法来设置它的值,这其实就是构造组件的部分
        public PhoneBuilder brand(String brand){
            this.brand = brand;
            // 返回自身,这样方便使用链式编程
            return this;
        }
        public PhoneBuilder memory(String memory){
            this.memory = memory;
            return this;
        }
        public PhoneBuilder screen(String screen){
            this.screen = screen;
            return this;
        }
        public PhoneBuilder camera(String camera){
            this.camera = camera;
            return this;
        }
        public PhoneBuilder clour(String clour){
            this.clour = clour;
            return this;
        }
        // 最后提供一个方法,创建产品对象,参数值就是上面的方法接受到的
        public Phone build(){
            return new Phone(brand, memory, screen, camera, clour);
        }
    }

    // 只为了测试方便,忽略
    @Override
    public String toString() {
        return "Phone{" +
                "brand='" + brand + '\'' +
                ", memory='" + memory + '\'' +
                ", screen='" + screen + '\'' +
                ", camera='" + camera + '\'' +
                ", clour='" + clour + '\'' +
                '}';
    }
}

只看这个类的设计会觉得很复杂,但是使用的时候就觉得爽了:

public class PhoneClient {
    public static void main(String[] args) {
        Phone phone = Phone.phoneBuilder()      // 这一步是得到它内部的一个构造器
                .brand("huawei")
                .clour("black")
//                .memory("64G")
//                .camera("1000 wan")
                .screen("18 ch")
                .build();       // 这一步才是真正创建一个Phone对象,并使用上面接受的参数

        System.out.println(phone);
    }
}

可以看到,在得到构造器和利用构造器创建对象中间,都是设置对象的属性值,最爽的地方就在于:随意。想设置几个就设置几个,而且顺序随意,而且代码可读性很好,很明确要给给哪些属性设置什么值。

其实这完全就是lomboc中的注解@Builder的功能。之前只是照着别人用觉得方便,也没有琢磨琢磨。最近学到了这个,觉得这个设计真是巧妙。平时工作中只是简单的crud,动脑筋比较少,多学学这些优秀的东西,真的可以开阔思路。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容