軟體設計模式白話文系列(五)建造者模式

2022-11-10 06:01:08

1、描述

將一個物件的構造過程進行封裝,並按照一定順序進行構造。

通俗的講,假如要建立電腦的物件,那麼各個範例的屬性不同,也就是電腦的設定各不相同.這個時候可以考慮用構造者模式。

2、適用性

當需要建立的物件建立過程複雜,如物件由多個部件構成,且各部件面臨著複雜的變化。

3、實現邏輯

  • 產品類:需要建立的物件。
  • 抽象建造者類:封裝構建步驟,定義產品物件的規範。
  • 具體建造者類:實現抽象建造者類,實現產品類的各個屬性的具體方法。在構造過程完成後,提供產品的範例。
  • 指揮者類:呼叫具體建造者類來建立複雜物件的各個部分,負責保證物件各部分完整建立或按某種順序建立。

4、實戰程式碼

用建造者模式建立 RabbitMQ 使用者端物件。

4.1 常規方式

/**
 * 產品類
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-09 19:19:15
 */
@Setter
public class RabbitMQ {
    private String host;
    private int port;
    private int mode;
    private String exchange;
    private String queue;
    private boolean durable;
    private int connectionTimeout;

    public void sendMessage(String msg) {
        System.out.println("傳送訊息:" + msg);
    }
}

/**
 * 抽象建造者類
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-09 19:17:04
 */
public abstract class Builder {
    protected RabbitMQ rabbitMQ= new RabbitMQ();

    public abstract void buildHost();
    public abstract void buildPort();
    public abstract void buildMode();
    public abstract void buildExchange();
    public abstract void buildQueue();
    public abstract void buildDurable();
    public abstract void buildConnectionTimeout();

    public abstract RabbitMQ createRabbitMQ();
}

/**
 * 具體建造者類
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-09 19:42:11
 */
public class MQBuilder extends Builder {
    @Override
    public void buildHost() {
        rabbitMQ.setHost("127.0.0.1");
    }

    @Override
    public void buildPort() {
        rabbitMQ.setPort(5672);
    }

    @Override
    public void buildMode() {
        rabbitMQ.setMode(1);
    }

    @Override
    public void buildExchange() {
        rabbitMQ.setExchange("exchange");
    }

    @Override
    public void buildQueue() {
        rabbitMQ.setQueue("test");
    }

    @Override
    public void buildDurable() {
        rabbitMQ.setDurable(true);
    }

    @Override
    public void buildConnectionTimeout() {
        rabbitMQ.setConnectionTimeout(3000);
    }

    @Override
    public RabbitMQ createRabbitMQ() {
        return rabbitMQ;
    }

}

/**
 * 指揮者類
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-09 19:55:33
 */
public class Director {
    private Builder builder;

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

    public RabbitMQ construct() {
        builder.buildHost();
        builder.buildPort();
        builder.buildMode();
        builder.buildExchange();
        builder.buildDurable();
        builder.buildQueue();
        builder.buildConnectionTimeout();

        return builder.createRabbitMQ();
    }
}

/**
 * 測試類
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-09 20:01:11
 */
public class Client {
    public static void main(String[] args) {
        MQBuilder mqBuilder = new MQBuilder();
        Director director = new Director(mqBuilder);
        RabbitMQ rabbitMQ = director.construct();
        rabbitMQ.sendMessage("測試物件");
    }
}

執行結果:

4.2 習慣性常用方式

上述常規方式中,我們需要每次都建立具體的構建類,這樣產品類的每個屬性都完全受具體構建類的控制,但是我們日常開發中,產品類的各個屬性幾乎都存在變化,所以可以這樣優化:

/**
 * 習慣性構建者方式
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-09 20:50:27
 */
public class RabbitMQ {

    private RabbitMQ(Builder builder) {

    }

    public void sendMessage(String msg) {
        System.out.println("傳送訊息:" + msg);
    }

    public static final class Builder {
        private String host;
        private int port;
        private int mode;
        private String exchange;
        private String queue;
        private boolean durable;
        private int connectionTimeout;

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

        public Builder port(int port) {
            this.port = port;
            return this;
        }

        public Builder mode(int mode) {
            this.mode = mode;
            return this;
        }

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

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

        public Builder durable(boolean durable) {
            this.durable = durable;
            return this;
        }

        public Builder connectionTimeout(int connectionTimeout) {
            this.connectionTimeout = connectionTimeout;
            return this;
        }

        public RabbitMQ build() {
            return new RabbitMQ(this);
        }
    }

}

執行結果:

這種方式,擺脫了超⻓構造⽅法引數的束縛的同時也保護了不可變物件的密閉性。

4.3 lombok Builder 方式

可以利用 lombok 外掛簡化程式碼

/**
 * lombok Builder 方式
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-09 21:04:11
 */
@Builder
public class RabbitMQ {
    private String host;
    private int port;
    private int mode;
    private String exchange;
    private String queue;
    private boolean durable;
    private int connectionTimeout;
}

/**
 * 測試類
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-09 20:01:11
 */
public class Client {
    public static void main(String[] args) {
        RabbitMQ rabbitMQ = RabbitMQ.builder()
                .host("127.0.0.1")
                .port(5462)
                .exchange("exchange")
                .durable(true)
                .mode(1)
                .queue("queue")
                .connectionTimeout(3000)
                .build();
        rabbitMQ.sendMessage("lombok Builder 方式");
    }
}

外掛自動生成程式碼

public class RabbitMQ {
    private String host;
    private int port;
    private int mode;
    private String exchange;
    private String queue;
    private boolean durable;
    private int connectionTimeout;

    public void sendMessage(String msg) {
        System.out.println("傳送訊息:" + msg);
    }

    RabbitMQ(String host, int port, int mode, String exchange, String queue, boolean durable, int connectionTimeout) {
        this.host = host;
        this.port = port;
        this.mode = mode;
        this.exchange = exchange;
        this.queue = queue;
        this.durable = durable;
        this.connectionTimeout = connectionTimeout;
    }

    public static RabbitMQ.RabbitMQBuilder builder() {
        return new RabbitMQ.RabbitMQBuilder();
    }

    public static class RabbitMQBuilder {
        private String host;
        private int port;
        private int mode;
        private String exchange;
        private String queue;
        private boolean durable;
        private int connectionTimeout;

        RabbitMQBuilder() {
        }

        public RabbitMQ.RabbitMQBuilder host(String host) {
            this.host = host;
            return this;
        }

        public RabbitMQ.RabbitMQBuilder port(int port) {
            this.port = port;
            return this;
        }

        public RabbitMQ.RabbitMQBuilder mode(int mode) {
            this.mode = mode;
            return this;
        }

        public RabbitMQ.RabbitMQBuilder exchange(String exchange) {
            this.exchange = exchange;
            return this;
        }

        public RabbitMQ.RabbitMQBuilder queue(String queue) {
            this.queue = queue;
            return this;
        }

        public RabbitMQ.RabbitMQBuilder durable(boolean durable) {
            this.durable = durable;
            return this;
        }

        public RabbitMQ.RabbitMQBuilder connectionTimeout(int connectionTimeout) {
            this.connectionTimeout = connectionTimeout;
            return this;
        }

        public RabbitMQ build() {
            return new RabbitMQ(this.host, this.port, this.mode, this.exchange, this.queue, this.durable, this.connectionTimeout);
        }

        public String toString() {
            return "RabbitMQ.RabbitMQBuilder(host=" + this.host + ", port=" + this.port + ", mode=" + this.mode + ", exchange=" + this.exchange + ", queue=" + this.queue + ", durable=" + this.durable + ", connectionTimeout=" + this.connectionTimeout + ")";
        }
    }
}

執行結果: