侧边栏壁纸
博主头像
昂洋编程 博主等级

鸟随鸾凤飞腾远,人伴贤良品自高

  • 累计撰写 71 篇文章
  • 累计创建 79 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

建造者模式

Administrator
2023-02-02 / 0 评论 / 0 点赞 / 94 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
本文最后更新于2024-06-14,若内容或图片失效,请留言反馈。 部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

介绍

建造者模式(builder pattern),也被称为生成器模式,是一种创建型设计模式,将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示

原理

image
建造者模式中有四个角色:产品、指挥者、抽象建造者、具体建造者,最终的产品是由指挥者根据具体的建造者构建产品。另外其实指挥者也不是一定需要,通常情况下可以通过客户端直接调用具体建造者,不需要通过指挥者,依据实际情况而论

建造者模式和工厂模式

工厂模式用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建那种类型的对象

建造者模式用来创建一种类型的复杂对象,通过设置不同的可选参数定制化的创建不同的对象

举例:顾客走进餐馆,利用工厂模式可以制作披萨、汉堡、沙拉等食物,利用建造者模式定制奶酪披萨、西红柿披萨、起司披萨等等

以下以摩拜单车和hello单车为例介绍第一种建造者模式

实现方式一

定义产品类

package com.imysh.zmy.mca.designpattern.builder.example01.product;

import lombok.Data;

/**
 * @author zhangmy
 * @date 2023/2/2 9:51
 * @description 产品类 -- 单车
 */
@Data
public class Bike {

    /**
     * 车架
     */
    private String frame;

    /**
     * 车座
     */
    private String seat;
}

定义抽象建造器

package com.imysh.zmy.mca.designpattern.builder.example01.builder;

import com.imysh.zmy.mca.designpattern.builder.example01.product.Bike;

/**
 * @author zhangmy
 * @date 2023/2/2 9:58
 * @description 抽象类建造器
 */
public abstract class Builder {

    /**
     * 实例化单车类共子类或实现类使用
     */
    protected Bike mBike = new Bike();

    /**
     * 建造车架
     * @return
     */
    public abstract void buildFrame();

    /**
     * 建造车座
     * @return
     */
    public abstract void buildSeat();

    /**
     * 建造单车
     * @return
     */
    public abstract Bike createBike();
}

定义具体建造器

  • 摩拜单车构建器
package com.imysh.zmy.mca.designpattern.builder.example01.builder;

import com.imysh.zmy.mca.designpattern.builder.example01.product.Bike;

/**
 * @author zhangmy
 * @date 2023/2/2 10:01
 * @description 摩拜单车构建器
 */
public class MoBikeBuilder extends Builder{

    @Override
    public void buildFrame() {
        System.out.println("建造车架");
        mBike.setFrame("铝合金车架");
    }

    @Override
    public void buildSeat() {
        System.out.println("建造车座");
        mBike.setSeat("真皮车座");
    }

    @Override
    public Bike createBike() {
        return mBike;
    }
}

  • Hello单车构建器
package com.imysh.zmy.mca.designpattern.builder.example01.builder;

import com.imysh.zmy.mca.designpattern.builder.example01.product.Bike;

/**
 * @author zhangmy
 * @date 2023/2/2 10:06
 * @description Hello单车构建器
 */
public class HelloBikeBuilder extends Builder{

    @Override
    public void buildFrame() {
        System.out.println("建造车架");
        mBike.setFrame("碳纤维车架");
    }

    @Override
    public void buildSeat() {
        System.out.println("建造车座");
        mBike.setSeat("橡胶车座");
    }

    @Override
    public Bike createBike() {
        return mBike;
    }
}

定义指挥者

package com.imysh.zmy.mca.designpattern.builder.example01.director;

import com.imysh.zmy.mca.designpattern.builder.example01.builder.Builder;
import com.imysh.zmy.mca.designpattern.builder.example01.product.Bike;

/**
 * @author zhangmy
 * @date 2023/2/2 10:14
 * @description 指挥者(智慧构建器去构建产品)
 */
public class Director {

    private Builder mBuilder;

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

    public Bike construct() {
        mBuilder.buildFrame();
        mBuilder.buildSeat();
        return mBuilder.createBike();
    }
}

使用客户端来生产产品

package com.imysh.zmy.mca.designpattern.builder.example01;

import com.imysh.zmy.mca.designpattern.builder.example01.builder.MoBikeBuilder;
import com.imysh.zmy.mca.designpattern.builder.example01.director.Director;
import com.imysh.zmy.mca.designpattern.builder.example01.product.Bike;

/**
 * @author zhangmy
 * @date 2023/2/2 10:22
 * @description 客户端(使用客户端来建造单车)
 */
public class Client {

    public static void main(String[] args) {
        // 创建指挥者 -- 摩拜建造器
        Director director = new Director(new MoBikeBuilder());
        // 建造单车
        Bike bike = director.construct();
        // 输出单车信息
        System.out.println("单车信息:" + bike.getFrame() + "," + bike.getSeat());
    }
}

可以看出来,我们通过不同建造器传入给指挥者,指挥者就能建造出我们需要的产品
image-1675309474050

另外建造者模式还有第二种常用实现,就是lombok中的@builder注解所做的事

实现方式二

对于参数较多的类,我们创建对象通常有两种方式:构造器、setter

  • 构造器
package com.imysh.zmy.mca.designpattern.builder.example02;

/**
 * @author zhangmy
 * @date 2023/2/2 10:40
 * @description rabbitMQ客户端对象 (方式一,使用构造方法创建)
 *
 * 当类的属性较多时,使用构造方法去实例化对象就需要传很多参数,可读性不强,并且有可能传错位置
 */
public class RabbitMqClient1 {

    private String host;

    private int port;

    private int mode;

    private String exchange;

    private String queue;

    private boolean isDurable;

    int connectionTimeout;

    public RabbitMqClient1(String host, int port, int mode, String exchange, String queue, boolean isDurable, int connectionTimeout) {
        this.host = host;
        this.port = port;
        this.mode = mode;
        this.exchange = exchange;
        this.queue = queue;
        this.isDurable = isDurable;
        this.connectionTimeout = connectionTimeout;
    }
}

当类的属性较多时,使用构造方法去实例化对象就需要传很多参数,可读性不强,并且有可能传错位置

  • setter
package com.imysh.zmy.mca.designpattern.builder.example02;

/**
 * @author zhangmy
 * @date 2023/2/2 10:40
 * @description rabbitMQ客户端对象 (方式二,使用set方法创建)
 *
 * 当类的属性较多时,使用set方法创建对象解决了可读性,但是实际上客户端创建之后属性就不能改变,不能通过set方法重复修改
 * 另外当需要对某一些属性做校验,而且这个校验还依赖前置属性 时,使用set方法就对顺序要求很高了,显然这不符合应用场景
 */
public class RabbitMqClient2 {

    private String host;

    private int port;

    private int mode;

    private String exchange;

    private String queue;

    private boolean isDurable;

    int connectionTimeout;

    public void setHost(String host) {
        this.host = host;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public void setMode(int mode) {
        this.mode = mode;
    }

    public void setExchange(String exchange) {
        this.exchange = exchange;
    }

    public void setQueue(String queue) {
        this.queue = queue;
    }

    public void setDurable(boolean durable) {
        isDurable = durable;
    }

    public void setConnectionTimeout(int connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }
}

类的属性较多时,使用set方法创建对象解决了可读性,但是实际上客户端创建之后属性就不能改变,不能通过set方法重复修改,另外当需要对某一些属性做校验,而且这个校验还依赖前置属性 时,使用set方法就对顺序要求很高了,显然这不符合应用场景

使用建造器模式创建复杂对象

四个步骤

  • 目标类的构造方法要传入一个Builder对象,并且构造方法私有;
  • Builder类位于目标类的内部,并且static修饰;
  • Builder类提供内置各种set方法,注意set方法返回值是builder本身;
  • Builder类提供build()方法,实现目标对象的创建;

具体实现

package com.imysh.zmy.mca.designpattern.builder.example02;

/**
 * @author zhangmy
 * @date 2023/2/2 10:40
 * @description rabbitMQ客户端对象 (方式三,使用建造者模式)
 *
 * 建造者模式
 *      1.目标类的构造方法要传入一个Builder对象,并且构造方法私有
 *      2.Builder类位于目标类的内部,并且static修饰
 *      3.Builder类提供内置各种set方法,注意set方法返回值是builder本身(为了可读性set方法名字可直接写成属性名)
 *      4.Builder类提供build()方法,实现目标对象的创建
 */
public class RabbitMqClient3 {

    /**
     * 1.私有化构造器
     */
    private RabbitMqClient3(Builder builder) {}

    /**
     * 额外优化,增加一个builder方法这样在外部创建时可以直接调用
     */
    public static Builder builder() {
        return new RabbitMqClient3.Builder();
    }

    /**
     * 2.Builder类位于目标类的内部,并且static修饰
     */
    static class Builder {

        private String host;

        private int port;

        private int mode;

        private String exchange;

        private String queue;

        private boolean isDurable;

        int connectionTimeout;

        /**
         * 3.Builder类提供内置各种set方法,注意set方法返回值是builder本身(为了可读性set方法名字可直接写成属性名)
         * @param host
         * @return
         */
        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) {
            isDurable = durable;
            return this;
        }

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

        /**
         * 4.Builder类提供build()方法,实现目标对象的创建
         * @return
         */
        public RabbitMqClient3 build() {
            // 在build方法里就可以去添加校验逻辑了

            // 返回新的RabbitMqClient3对象
            return new RabbitMqClient3(this);
        }

        @Override
        public String toString() {
            return "Builder{" +
                    "host='" + host + '\'' +
                    ", port=" + port +
                    ", mode=" + mode +
                    ", exchange='" + exchange + '\'' +
                    ", queue='" + queue + '\'' +
                    ", isDurable=" + isDurable +
                    ", connectionTimeout=" + connectionTimeout +
                    '}';
        }
    }
}

使用就是那种链式创建了

package com.imysh.zmy.mca.designpattern.builder.example02;

/**
 * @author zhangmy
 * @date 2023/2/2 11:07
 * @description 客户端 -- 使用建造者模式去创建对象
 */
public class Client {

    public static void main(String[] args) {
        RabbitMqClient3 client = RabbitMqClient3.builder()
                .host("127.0.0.1")
                .port(5672)
                .mode(1)
                .exchange("ex1")
                .queue("q1")
                .durable(true)
                .connectionTimeout(5000)
                .build();
    }
}

关于第二种建造者模式的使用可以安靠lombok的@builder注解的具体生成代码

0

评论区