【Java开发】设计模式 03:建造者模式

1 建造者模式介绍

建造者模式使用多个简单的对象一步一步构建成一个复杂的对象。

当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。

场景

当一个类的构造函数参数超过4个,而且这些参数有些是可选的时,我们通常有两种办法来构建它的对象。 例如我们现在有如下一个类计算机类Computer,其中cpu与ram是必填参数,而其他3个是可选参数,那么我们如何构造这个类的实例呢,通常有两种常用的方式:

public class Computer {
    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选
    private String keyboard;//可选
    private String display;//可选
}

① 折叠构造函数模式

public class Computer {

    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选,默认为0
    private String keyboard;//可选,默认为罗技键盘
    private String display;//可选,默认为三星显示器

    public Computer(String cpu, String ram) {
        this(cpu, ram, 0);
    }
    public Computer(String cpu, String ram, int usbCount) {
        this(cpu, ram, usbCount, "罗技键盘");
    }
    public Computer(String cpu, String ram, int usbCount, String keyboard) {
        this(cpu, ram, usbCount, keyboard, "三星显示器");
    }
    public Computer(String cpu, String ram, int usbCount, String keyboard, String display) {
        this.cpu = cpu;
        this.ram = ram;
        this.usbCount = usbCount;
        this.keyboard = keyboard;
        this.display = display;
    }
}

② Javabean模式

public class Computer {

    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选
    private String keyboard;//可选
    private String display;//可选

    public String getCpu() {
        return cpu;
    }
    public void setCpu(String cpu) {
        this.cpu = cpu;
    }
    public String getRam() {
        return ram;
    }
    public void setRam(String ram) {
        this.ram = ram;
    }
    public int getUsbCount() {
        return usbCount;
    }
...
}

这也可用lombok依赖包的@Data注解替代~

两种方式的弊端

第一种使用和阅读不方便,当使用该类的构造函数时,需要搞清楚各参数的含义,而且还是按照严格的顺序。

第二种由于类的属性是分布设置的,那么构建过程中对象的状态容易发生变化,容易出错。

那么builder模式可以较好地解决以上问题!

2 构建者模式实现

步骤

  1. 在Computer 中创建一个静态内部类 Builder,然后将Computer 中的参数都复制到Builder类中。

  1. 在Computer中创建一个private的构造函数,参数为Builder类型

  1. 在Builder中创建一个public的构造函数,参数为Computer中必填的那些参数,cpu 和ram。

  1. 在Builder中创建设置函数,对Computer中那些可选参数进行赋值,返回值为Builder类型的实例

  1. 在Builder中创建一个build()方法,在其中构建Computer的实例并返回

也可直接使用lombok依赖包的@Builder注解一键解决。

具体代码

public class Computer {
    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选,默认为0
    private String keyboard;//可选,默认为罗技键盘
    private String display;//可选,默认为三星显示器

    private Computer(Builder builder){
        this.cpu=builder.cpu;
        this.ram=builder.ram;
        this.usbCount=builder.usbCount;
        this.keyboard=builder.keyboard;
        this.display=builder.display;
    }
    public static class Builder{
        private String cpu;//必须
        private String ram;//必须
        private int usbCount;//可选
        private String keyboard;//可选
        private String display;//可选

        public Builder(String cup,String ram){
            this.cpu=cup;
            this.ram=ram;
        }

        public Builder setUsbCount(int usbCount) {
            this.usbCount = usbCount;
            return this;
        }
        public Builder setKeyboard(String keyboard) {
            this.keyboard = keyboard;
            return this;
        }
        public Builder setDisplay(String display) {
            this.display = display;
            return this;
        }
        public Computer build(){
            return new Computer(this);
        }
    }
}

使用

Computer computer = new Computer.Builder("AMD","小米")
        .setUsbCount(0)
        .setKeyboard("罗技")
        .setDisplay("三星24寸").build();

@Builder注解一键解决

@Builder
public class Computer {
    private String cpu;//可选
    private String ram;//可选
    private int usbCount;//可选
    private String keyboard;//可选
    private String display;//可选
}

class test{
    public static void main(String[] args) {
        Computer computer = Computer.builder().cpu("AMD").ram("金士顿")
                .usbCount(0)
                .keyboard("罗技")
                .display("三星24寸")
                .build();
    }
}

使用方式稍微不一样~

3 传统建造者模式

上面的内容是Builder在Java中一种简化的使用方式,经典的Builder 模式与其有一定的不同,如UML图:

【Java开发】设计模式 03:建造者模式_第1张图片

各角色

  • Product: 最终要生成的对象,例如 Computer实例。

  • Builder: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product getProduct(),例如 ComputerBuilder抽象类。

  • ConcreteBuilder: Builder的实现类,如LenovoComputerBuilder类和MacComputerBuilder类。

  • Director: 决定如何构建最终产品的算法, 其会包含一个负责组装的方法void Construct(Builder builder), 在这个方法中通过调用builder的方法,就可以设置builder,例如 ComputerDirector类。

等设置完成后,就可以通过builder的 getProduct() 方法获得最终的产品。

1.目标Computer类

public class Computer {
    private String cpu;//必须
    private String ram;//必须
    private int usbCount;//可选,默认为0
    private String keyboard;//可选,默认为罗技键盘
    private String display;//可选,默认为三星显示器

    public Computer(String cpu, String ram) {
        this.cpu = cpu;
        this.ram = ram;
    }
    public void setUsbCount(int usbCount) {
        this.usbCount = usbCount;
    }
    public void setKeyboard(String keyboard) {
        this.keyboard = keyboard;
    }
    public void setDisplay(String display) {
        this.display = display;
    }
    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", ram='" + ram + '\'' +
                ", usbCount=" + usbCount +
                ", keyboard='" + keyboard + '\'' +
                ", display='" + display + '\'' +
                '}';
    }
}

2.抽象构建者类

public abstract class ComputerBuilder {

    public abstract void setUsbCount();
    public abstract void setKeyboard();
    public abstract void setDisplay();

    public abstract Computer getComputer();
}

3.实体构建者类

public class LenovoComputerBuilder extends ComputerBuilder{
    private Computer computer;
    public LenovoComputerBuilder(String cpu, String ram) {
        computer=new Computer(cpu,ram);
    }
    @Override
    public void setUsbCount() {
        computer.setUsbCount(4);
    }
    @Override
    public void setKeyboard() {
        computer.setKeyboard("联想键盘");
    }
    @Override
    public void setDisplay() {
        computer.setDisplay("联想显示器");
    }
    @Override
    public Computer getComputer() {
        return computer;
    }
}
public class MacComputerBuilder extends ComputerBuilder{

    private Computer computer;

    public MacComputerBuilder(String cpu, String ram) {
        computer = new Computer(cpu, ram);
    }

    @Override
    public void setUsbCount() {
        computer.setUsbCount(2);
    }
    @Override
    public void setKeyboard() {
        computer.setKeyboard("苹果键盘");
    }
    @Override
    public void setDisplay() {
        computer.setDisplay("苹果显示器");
    }
    @Override
    public Computer getComputer() {
        return computer;
    }
}

4.指导者类(Director)

public class ComputerDirector {
    public void makeComputer(ComputerBuilder builder){
        builder.setUsbCount();
        builder.setDisplay();
        builder.setKeyboard();
    }
}

5.使用

首先生成一个director,然后生成一个目标builder ,接着使用director组装builder,组装完毕后使用builder创建产品实例。

    ComputerDirector director = new ComputerDirector();//1
    
    ComputerBuilder macBuilder = new MacComputerBuilder("I5处理器","三星125");//2
    director.makeComputer(macBuilder);//3
    Computer macComputer=macBuilder.getComputer();//4
    System.out.println("mac computer:"+macComputer.toString());
    
    ComputerBuilder lenovoBuilder=new LenovoComputerBuilder("I7处理器","海力士222");
    director.makeComputer(lenovoBuilder);
    Computer lenovoComputer=lenovoBuilder.getComputer();
    System.out.println("lenovo computer:"+lenovoComputer.toString());

总结

其实之前用的是的变种, 首先其省略了director 这个角色,将构建算法交给了client端,其次将builder 写到了要构建的产品类里面,最后采用了链式调用。

你可能感兴趣的:(设计模式,建造者模式,开发语言,java)