掌握设计模式之生成器模式

本文的主要内容有:
image

生成器模式(Builder Pattern)

意图

将复杂对象的构造与其表示分开,使得相同的构造过程可以创建不同的表示。

适用性

适用于需要创建复杂对象,对象的构建过程比较灵活,可以通过多个步骤逐步完成。

案例一:参数传递方式

案例概述

使用多个零部件组装成一台的手机,不同型号或品牌的手机由不同的零部件构成。

案例类图

image

案例代码

// 手机产品
class Phone {
    private Screen screen;
    private Battery battery;
    private Cpu cpu;
    private Camera camera;

    // 打印产品详情信息
    public String getSpecification() {
        return new StringBuilder("手机规格:\n")
                .append(" - ").append(this.screen).append("\n")
                .append(" - ").append(this.battery).append("\n")
                .append(" - ").append(this.cpu).append("\n")
                .append(" - ").append(this.camera).append("\n")
                .append("\n").toString();
    }

    public void setScreen(Screen screen) {
        this.screen = screen;
    }

    public void setBattery(Battery battery) {
        this.battery = battery;
    }

    public void setCpu(Cpu cpu) {
        this.cpu = cpu;
    }

    public void setCamera(Camera camera) {
        this.camera = camera;
    }
}

// 具体零部件--显示屏
class Screen {
    private String name;
    private String distinguishability;

    public Screen(String name, String distinguishability) {
        this.name = name;
        this.distinguishability = distinguishability;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("Screen{");
        sb.append("name='").append(name).append('\'');
        sb.append(", distinguishability='").append(distinguishability).append('\'');
        sb.append('}');
        return sb.toString();
    }

    // 省略get set...
}

// 具体零部件--电池
class Battery{
    private String name;
    private String capacity;

    public Battery(String name, String capacity) {
        this.name = name;
        this.capacity = capacity;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("Battery{");
        sb.append("name='").append(name).append('\'');
        sb.append(", capacity='").append(capacity).append('\'');
        sb.append('}');
        return sb.toString();
    }

    // 省略get set...
}

// 具体零部件--芯片
class Cpu{
    private String name;
    private String version;

    public Cpu(String name, String version) {
        this.name = name;
        this.version = version;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("Cpu{");
        sb.append("name='").append(name).append('\'');
        sb.append(", version='").append(version).append('\'');
        sb.append('}');
        return sb.toString();
    }

    // 省略get set...
}

// 具体零部件--摄像头
class Camera{
    private String name;
    private String pixel;

    public Camera(String name, String pixel) {
        this.name = name;
        this.pixel = pixel;
    }

    @Override
    public String toString() {
        final StringBuffer sb = new StringBuffer("Camera{");
        sb.append("name='").append(name).append('\'');
        sb.append(", pixel='").append(pixel).append('\'');
        sb.append('}');
        return sb.toString();
    }

    // 省略get set...
}


// 生成器接口
interface PhoneBuilder {
    PhoneBuilder buildScreen(Screen screen);
    PhoneBuilder buildBattery(Battery battery);
    PhoneBuilder buildCpu(Cpu cpu);
    PhoneBuilder buildCamera(Camera camera);
    Phone getPhone();
}


// 具体生成器
class ConcretePhoneBuilder implements PhoneBuilder {
    private Phone phone = new Phone();

    @Override
    public PhoneBuilder buildScreen(Screen screen) {
        phone.setScreen(screen);
        return this;
    }

    @Override
    public PhoneBuilder buildBattery(Battery battery) {
        phone.setBattery(battery);
        return this;
    }

    @Override
    public PhoneBuilder buildCpu(Cpu cpu) {
        phone.setCpu(cpu);
        return this;
    }

    @Override
    public PhoneBuilder buildCamera(Camera camera) {
        phone.setCamera(camera);
        return this;
    }

    @Override
    public Phone getPhone() {
        return phone;
    }
}


// Director 类
class Director {
    // 构建手机的方法
    public static void construct(PhoneBuilder phoneBuilder) {
        phoneBuilder.buildScreen(new Screen("三星屏幕","2k分辨率"))
                .buildBattery(new Battery("国产电池","5400毫安"))
                .buildCpu(new Cpu("骁龙CPU", "骁龙8+"))
                .buildCamera(new Camera("徕卡摄像头","一亿像素"));
    }
    public static void constructXl(PhoneBuilder phoneBuilder) {
        phoneBuilder.buildScreen(new Screen("国产屏幕","2k分辨率"))
                .buildBattery(new Battery("国产电池","4800毫安"))
                .buildCpu(new Cpu("麒麟CPU","9000"))
                .buildCamera(new Camera("徕卡摄像头","两亿像素"));
    }
}


// 测试类
public class BuilderDemo {
    public static void main(String[] args) {
        PhoneBuilder phoneBuilder = new ConcretePhoneBuilder();
        Director.construct(phoneBuilder);//执行构建:该产品的生产过程
        Phone phone = phoneBuilder.getPhone();// 获取构建结果:获取产品
        System.out.println(phone.getSpecification());

        Director.constructXl(phoneBuilder);
        Phone phone1 = phoneBuilder.getPhone();
        System.out.println(phone1.getSpecification());

    }
}

案例简析

Director类通过生成器传参的方式,调用具体生成器ConcretePhoneBuilder 类的方法来构建一个复杂的对象Phone。这种传参的生成器方式其实可以不需要PhoneBuilder接口,直接使用具体生成器ConcretePhoneBuilder即可。

这种生成器方式在Spring、SpringSecurity、MyBatis等框架中经常用到,比如

SpringSecurity下的身份验证管理器生成器 AuthenticationManagerBuilder类

image

Spring下的Bean定义构建器BeanDefinitionBuilder类

image

还有一种通过编码方式来实现生成器。

案例二:编码的方式

案例概述

使用相同的构建过程,生成两款不同配置的电脑。

案例类图

image

案例代码

// 产品:电脑
class Computer {
    private String CPU;
    private String GPU;
    private int RAM;
    private int storage;

    public void setCPU(String CPU) {
        this.CPU = CPU;
    }

    public void setGPU(String GPU) {
        this.GPU = GPU;
    }

    public void setRAM(int RAM) {
        this.RAM = RAM;
    }

    public void setStorage(int storage) {
        this.storage = storage;
    }

    @Override
    public String toString() {
        return "Computer{" +
                "CPU='" + CPU + '\'' +
                ", GPU='" + GPU + '\'' +
                ", RAM=" + RAM +
                ", storage=" + storage +
                '}';
    }
}

// 抽象生成器
interface ComputerBuilder {
    void buildCPU();
    void buildGPU();
    void buildRAM();
    void buildStorage();
    Computer getComputer();
}

// 具体生成器:高端电脑生成器
class HighEndComputerBuilder implements ComputerBuilder {
    private Computer computer;

    public HighEndComputerBuilder() {
        this.computer = new Computer();
    }

    @Override
    public void buildCPU() {
        computer.setCPU("高端电脑 CPU");
    }

    @Override
    public void buildGPU() {
        computer.setGPU("高端电脑 GPU");
    }

    @Override
    public void buildRAM() {
        computer.setRAM(32);
    }

    @Override
    public void buildStorage() {
        computer.setStorage(1000);
    }

    @Override
    public Computer getComputer() {
        return computer;
    }
}

// 具体生成器:标准电脑生成器
class StandardComputerBuilder implements ComputerBuilder {
    private Computer computer;

    public StandardComputerBuilder() {
        this.computer = new Computer();
    }

    @Override
    public void buildCPU() {
        computer.setCPU("标准电脑 CPU");
    }

    @Override
    public void buildGPU() {
        computer.setGPU("标准电脑 GPU");
    }

    @Override
    public void buildRAM() {
        computer.setRAM(8);
    }

    @Override
    public void buildStorage() {
        computer.setStorage(500);
    }

    @Override
    public Computer getComputer() {
        return computer;
    }
}

// Director 类
class ComputerDirector {
    private ComputerBuilder computerBuilder;

    public ComputerDirector(ComputerBuilder computerBuilder) {
        this.computerBuilder = computerBuilder;
    }
    // 统一的构建过程
    public void buildComputer() {
        computerBuilder.buildCPU();
        computerBuilder.buildGPU();
        computerBuilder.buildRAM();
        computerBuilder.buildStorage();
    }

    public Computer getComputer() {
        return computerBuilder.getComputer();
    }
}

// 客户端代码
public class BuilderDemo2 {
    public static void main(String[] args) {
        // 构建高端电脑
        ComputerBuilder highEndBuilder = new HighEndComputerBuilder();
        ComputerDirector highEndDirector = new ComputerDirector(highEndBuilder);
        highEndDirector.buildComputer();
        Computer highEndComputer = highEndDirector.getComputer();
        System.out.println("高端电脑: " + highEndComputer);

        // 构建标准电脑
        ComputerBuilder standardBuilder = new StandardComputerBuilder();
        ComputerDirector standardDirector = new ComputerDirector(standardBuilder);
        standardDirector.buildComputer();
        Computer standardComputer = standardDirector.getComputer();
        System.out.println("标准电脑: " + standardComputer);
    }
}

案例简析

HighEndComputerBuilderStandardComputerBuilder 生成器实现了ComputerBuilder接口,并在具体生成器中使用硬编码的方式编写好了每一步。ComputerDirector类使用统一的构建过程buildComputer()来生产不同的复杂对象Computer

这种生成器方式在Spring、MyBatis等框架中也经常用到,比如:MyBatis 通过解析XML文件配置来构建对象的XMLConfigBuilder

image

注意,同一个构建过程,根据不同的生成器生成不同的复杂对象信息。在新增了新的生成器时,这个构建过程是不需要修改的,这就区别于案例一的参数传递的方式。这里的硬编码也可以通过获取配置文件内容读取数据库数据来赋值。

总结

生成器的重点关注如何分步生成复杂对象,其生成方式并不固定必须怎么做,向符合设计原则解决设计问题的方向靠即可。

以上两种方式之间的主要区别在于:

  • 硬编码的方式: 往往用于通过配置文件生成复杂对象,一般有生成器接口

    • 在具体生成器类中"硬编码"构建过程的每个步骤,每个具体生成器都有其独特的构建逻辑。
    • 适用于每个具体生成器都有不同构建过程的情况。

    具体示例可阅读MyBatis 的抽象接口BaseBuilder及其具体生成器类。比如,XMLConfigBuilder类用于解析xml配置文件生成Configuration对象并注册各种配置到Configuration对象中和解析环境配置等。而其他的生成器则实现了其独特的构建逻辑。

  • 传递参数的方式: 代码传参自定义生成复杂对象,一般无需抽象接口

    • 通过在构造函数中传递参数,使得构建逻辑变得更加灵活,可以动态指定要构建的对象的属性。
    • 适用于多个生成器共享相似构建逻辑,但具体参数可能有所不同。

    具体示例可阅读Spring的BeanDefinitionBuilder类。BeanDefinitionBuilder 类提供了一种流式的、更简洁的方式来构建 BeanDefinition对象,该方式由调用者传参来决定生成怎样的BeanDefinition对象。

选择使用哪种方式取决于具体的需求。如果每个具体生成器都有自己独特的构建逻辑,“硬编码的方式”可能更为合适。如果多个生成器之间有相似的构建逻辑,但具体参数不同,传递参数的方式可能更为灵活。

image

什么是设计模式?

单例模式及其思想

设计模式--原型模式及其编程思想

超实用的SpringAOP实战之日志记录

2023年下半年软考考试重磅消息

通过软考后却领取不到实体证书?

计算机算法设计与分析(第5版)

Java全栈学习路线、学习资源和面试题一条龙

软考证书=职称证书?

软考中级--软件设计师毫无保留的备考分享

posted @ 2024-12-02 22:04  渊渟岳  阅读(19)  评论(0编辑  收藏  举报