Tip:考虑使用Builder模式

372 阅读2分钟

考虑使用Builder模式

日常开发中,大部分都基于构造方法或普通的javabean set方式来创建填充对象。

当参数众多类型相同,同时包含一些必填与非必填参数等情况时,Builder模式是一个很好的实践方式。

案例:

设计创建配备一台PC电脑,其中显示屏/主机/鼠标/键盘作为必填的属性; 而音箱/摄像头等作为非必填属性。 我们分别通过构造方法,javabean set,以及Builder三种模式来创建进行对比。

public class TestPcComputer {

    private String dispaly;
    private String host;
    private String keyboard;
    private String mouse;
    // 非必填
    private String speaker;
    private String camera;

}
1. 通过构造方法
public TestPcComputer(String dispaly, String host, String keyboard, String mouse) {
    this.dispaly = dispaly;
    this.host = host;
    this.keyboard = keyboard;
    this.mouse = mouse;
}

public TestPcComputer(String dispaly, String host, String keyboard, String mouse, String speaker) {
    this.dispaly = dispaly;
    this.host = host;
    this.keyboard = keyboard;
    this.mouse = mouse;
    this.speaker = speaker;
}

public TestPcComputer(String dispaly, String host, String keyboard, String mouse, String speaker, String camera) {
    this.dispaly = dispaly;
    this.host = host;
    this.keyboard = keyboard;
    this.mouse = mouse;
    this.speaker = speaker;
    this.camera = camera;
}

为了支持必填与非必填属性,对构造方法进行重载。比如我们创建一个包含camera的电脑:

TestPcComputer pc = new TestPcComputer("显示器", "主机", "键盘", "鼠标",  null, "摄像头")

可以看到当我们只包含其中一些非必填字段时,需要根据构造方法的签名,将不包含的非必填字段也进行传值。

另外,如果客户端调用创建对象没有文档或源码, 只是看到构造方法分别有不同数量的string类型简直就是。。。

2. 通过JavaBean set方式

针对上面的属性分别生成get()&set()方法(此处省略代码部分)。

同样我们创建一个包含camera的电脑:

TestPcComputer pc = new TestPcComputer();
pc.setDispaly("显示器");
pc.setHost("主机");
pc.setKeyboard("键盘");
pc.setMouse("鼠标");
pc.setCamera("摄像头");

可以看到比构造方法可读性要好,但是分不清哪些是必填的哪些是可选的。 另外在pc对象完成构造之后还是可变的。

3. 通过Builder方式

创建Builder内部构造类:

public class TestPcComputer {
    
    ... //省略属性
    
    public static class Builder {
        private String dispaly;
        private String host;
        private String keyboard;
        private String mouse;

        private String speaker;
        private String camera;

        public Builder(String dispaly, String host, String keyboard, String mouse) {
            this.dispaly = dispaly;
            this.host = host;
            this.keyboard = keyboard;
            this.mouse = mouse;
        }

        public Builder speaker(String speaker) {
            this.speaker = speaker;
            return this;
        }

        public Builder camera(String camera) {
            this.camera = camera;
            return this;
        }

        public TestPcComputer build() {
            TestPcComputer pc = new TestPcComputer();
            pc.setDispaly(this.dispaly);
            pc.setHost(this.host);
            pc.setKeyboard(this.keyboard);
            pc.setMouse(this.mouse);
            pc.setCamera(this.camera);
            return pc;
        }
    }

}

同样我们创建一个包含camera的电脑:

TestPcComputer pc = new TestPcComputer.Builder("显示器", "主机", "键盘", "鼠标")
                .camera("摄像头").build();

可以看到使用Builder模式后,客户端创建对象时代码更容易编写及可读。 当增加更多的可选属性时也更容易扩展。

总结

  1. 对于一些简单的对象创建使用构造方法或set方式更好。
  2. 对于一些对象需要定制化参数,可以借助Builder模式更好的描述创建的过程。
  3. 使用Builder也需要付出一些代价,如:每次会多创建一个Builder对象。