一、前言
什么是建造者模式?或许我们对这个模式一点都不了解的。但链式调用你总写过吧,那就是建造者模式。
我举个栗子:
这是一个okhttp3使用的栗子:
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .addHeader("Cookie", cookieString)
                .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko")
                .build();  让我们深入Request类的内部,仅保留了url字段,简化后的Request如下:
public final class Request {
    private final HttpUrl url;
    private Request(Builder builder) {
        this.url = builder.url;
    }
    public HttpUrl url() {
        return this.url;
    }
    public static class Builder {
        private HttpUrl url;
        public Builder url(HttpUrl url) {
            if (url == null) {
                throw new NullPointerException("url == null");
            } else {
                this.url = url;
                return this;
            }
        }
        public Request build() {
            if (this.url == null) {
                throw new IllegalStateException("url == null");
            } else {
                return new Request(this);
            }
        }
    }
}
  我们可以发现:
- Request类中有一个静态内部类Builder,Builder类中的属性和Request类一一对应。
 - Request类的构造方法接收的是一个Builder对象。
 - Builder类中每一个设置属性的方法返回值都是Builder对象本身。
 - Builder类中的build()方法调用Request类的构造方法,将Builder对象本身传入。
 
看的出来,建造者模式一步一步地将简单的对象构造成复杂的对象,我们熟悉的链式调用,就是建造者模式。
建造者模式本来应该有多个角色:
- Product 产品类,我们最终需要的产品,对应这里的Request
 - AbstractBuilder 抽象的建造者,规范产品的组件
 - ConcreteBuilder 具体的建造者,实现抽象的建造者中的方法,最后返回一个产品。对应这里的Builder
 - Director 导演,封装了建造者,用于通知建造者开始建造
 
但随着建造者模式的简化,其中的AbstractBuilder、Director的概念已经淡化,或者说用得不多。最终演变成只有一个产品类,以及产品类中的静态建造者类。
二、实例演示
这里我们建造一个电脑,电脑由显示器、机箱、键盘和鼠标构成。
package com.yang.testBuilder;
public class Computer {
    /**
     * 显示器
     */
    private String monitor;
    /**
     * 机箱
     */
    private String box;
    /**
     * 键盘
     */
    private String keyboard;
    /**
     * 鼠标
     */
    private String mouse;
    public Computer(Builder builder) {
        this.monitor = builder.monitor;
        this.box = builder.box;
        this.keyboard = builder.keyboard;
        this.mouse = builder.mouse;
    }
    public String getMonitor() {
        return monitor;
    }
    public String getBox() {
        return box;
    }
    public String getKeyboard() {
        return keyboard;
    }
    public String getMouse() {
        return mouse;
    }
    @Override
    public String toString() {
        return "Computer{" +
                "monitor='" + monitor + '\'' +
                ", box='" + box + '\'' +
                ", keyboard='" + keyboard + '\'' +
                ", mouse='" + mouse + '\'' +
                '}';
    }
    static class Builder {
        /**
         * 显示器
         */
        private String monitor;
        /**
         * 机箱
         */
        private String box;
        /**
         * 键盘
         */
        private String keyboard;
        /**
         * 鼠标
         */
        private String mouse;
        public Builder monitor(String monitor) {
            this.monitor = monitor;
            return this;
        }
        public Builder box(String box) {
            this.box = box;
            return this;
        }
        public Builder keyboard(String keyboard) {
            this.keyboard = keyboard;
            return this;
        }
        public Builder mouse(String mouse) {
            this.mouse = mouse;
            return this;
        }
        public Computer build() {
            return new Computer(this);
        }
    }
}
  测试:
package com.yang.testBuilder;
public class TestBuilderMain {
    public static void main(String[] args) {
        Computer computer = new Computer.Builder()
                .monitor("显示器")
                .box("机箱")
                .keyboard("键盘")
                .mouse("鼠标").build();
        System.out.println(computer);
    }
}
  输出:
链式调用的好处在哪里?
链式调用比(无参构造方法+一个一个set)更加节省代码,更加简便。
链式调用比普通的全参构造方法更加简明,全参构造方法需要将参数设置进对应的位置上,在idea中,我们需要按照ctrl+p才能显示当前参数的名称,这一点没有链式调用方便。

京公网安备 11010502036488号