设计模式-生成器模式的实现[JAVA]

设计模式-生成器模式的实现[JAVA]

摘要

The builder pattern is a design pattern designed to provide a flexible solution to various object creation problems in object-oriented programming. The intent of the Builder design pattern is to separate the construction of a complex object from its representation. It is one of the Gang of Four design patterns.
可以简单理解为:生成器模式是解决复杂对象创建一种手段,把复杂对象的创建和表示分离,进行解耦,那么为什么要把创建和表示分离呢,因为一旦一个对象有几十个属性需要在构造函数里上送,写起来就很麻烦,也容易出错。

引言

使用一般方式创建复杂对象

  • 示例 1
/**
 * 简单演示普通创建对象的方式复杂性
 * @Author: Shiraki
 * @Date: 2020/9/16 13:42
 */
public class DemoBuilder {
    public static void main(String[] args) {
        System.out.println(
                "CellPhone: " + 
                        new CellPhone(new Company("huawei", "010101", "mail.huawei.com"), 
                        new NetworkType(),
                        new Color(), 10, 20.0));
    }
}
class CellPhone {
    // 生产商
    private Company manufacturer;
    // 网络类型
    private NetworkType networkType;
    // 颜色
    private Color color;
    // 重量
    private int weight;
    // 价格
    private Double price;

    // 普通的构建方法
    CellPhone(Company manufacturer, NetworkType networkType, Color color, int weight, Double price) {
        this.manufacturer = manufacturer;
        this.networkType = networkType;
        this.color = color;
        this.weight = weight;
        this.price = price;
    }

    @Override
    public String toString() {
        return "CellPhone{" +
                "manufacturer=" + manufacturer +
                ", networkType=" + networkType +
                ", color=" + color +
                ", weight=" + weight +
                ", price=" + price +
                '}';
    }
}

class Company {
    // 公司名称
    private String name = "unknown";
    // 公司代码
    private String code = "unknown";
    // 公司邮箱
    private String mail = "unknown";

    public Company(String name, String code, String mail) {
        this.name = name;
        this.code = code;
        this.mail = mail;
    }

    @Override
    public String toString() {
        return "Company{" +
                "name='" + name + '\'' +
                ", code='" + code + '\'' +
                ", mail='" + mail + '\'' +
                '}';
    }
}

class NetworkType {
    // 运行商
    private Company isp = new Company("China Mobile", "10086", "mail.10086.cn");
    private String type;
    @Override
    public String toString() {
        return "NetworkType{" +
                "isp=" + isp +
                ", type='" + type + '\'' +
                '}';
    }
}

class Color {
    private int red;
    private int green;
    private int blue;
    @Override
    public String toString() {
        return "Color{" +
                "red=" + red +
                ", green=" + green +
                ", blue=" + blue +
                '}';
    }
}


示例1中创建一个手机需要设置好多个属性,如生产商、网络类型、颜色、重量等。该例子中手机就是一个复杂类型。如果通过普通的构造函数进行初始化,代码写起来非常麻烦,同时还需要调用方去维护CompanyNetworkTypeColor等辅助创建手机的类。那么有什么办法可以解决这个问题呢?
答案是生成器-Builder模型。

生成器Builder模式

基本的生成器模型

1. 类图
在这里插入图片描述

Builder抽象负责对象熟悉分类
Direct 通过builder实例进行特征对象构建-简化对象构建,提供一个类似模板的方法construct
ConcreteBuilder实际生成器,构建实际产品,但是往往这是构建的产品也是一个抽象产品Iproduct
Product实际产品,一般开发中此处为产品接口

2. 实现
实现类图:
在这里插入图片描述

此处也能看出产品ProductCellPhone只是一个抽象接口。实际通过CellPhone接口去创建HuaWeCellPhone

代码如下:

/**
 * 通过构建华为手机来掩饰生成器模型 
 * @Author: Shiraki
 * @Date: 2020/9/16 13:42
 */
public class DemoBuilder {
    public static void main(String[] args) {
        CellBuilder builder = new HuaWeiCellPhoneBuilder();
        // 通过HonorCellPhoneDirect
        HonorCellPhoneDirect direct = new HonorCellPhoneDirect(builder);
        direct.construct("China Union", "5G");
        System.out.println("direct.cellBuilder.build() = " + direct.cellBuilder.build());
    }
}

abstract class CellPhone {
    // 生产商
    private Company manufacturer;
    // 网络类型
    private NetworkType networkType;
    // 颜色
    private Color color;
    // 重量
    private int weight;
    // 价格
    private Double price;
    // logo

    abstract String getLog();
    protected CellPhone() {
    }

    @Override
    public String toString() {
        return "\nCellPhone{" +
                "\n\tmanufacturer=" + manufacturer +
                "\n\tnetworkType=" + networkType +
                "\n\tcolor=" + color +
                "\n\tweight=" + weight +
                "\n\tprice=" + price +
                "\n}";
    }

    public Company getManufacturer() {
        return manufacturer;
    }

    public void setManufacturer(Company manufacturer) {
        this.manufacturer = manufacturer;
    }

    public NetworkType getNetworkType() {
        return networkType;
    }

    public void setNetworkType(NetworkType networkType) {
        this.networkType = networkType;
    }

    public Color getColor() {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public int getWeight() {
        return weight;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}

class HuaWeiCellPhone extends CellPhone {

    @Override
    String getLog() {
        return "菊花";
    }
}
// 公司
class Company {
    // 公司名称
    private String name = "unknown";
    // 公司代码
    private String code = "unknown";
    // 公司邮箱
    private String mail = "unknown";

    public Company(String name, String code, String mail) {
        this.name = name;
        this.code = code;
        this.mail = mail;
    }

    @Override
    public String toString() {
        return "Company{" +
                "name='" + name + '\'' +
                ", code='" + code + '\'' +
                ", mail='" + mail + '\'' +
                '}';
    }
}

// 网络
class NetworkType {
    // 运营商
    private Company isp;
    private String type;

    @Override
    public String toString() {
        return "NetworkType{" +
                "isp=" + isp +
                ", type='" + type + '\'' +
                '}';
    }

    public NetworkType(Company isp, String type) {
        this.isp = isp;
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

class Color {
    public Color(int red, int green, int blue) {
        this.red = red;
        this.green = green;
        this.blue = blue;
    }

    // 默认白色
    private int red = 255;
    private int green = 255;
    private int blue = 255;
}

// 生成器接口 --调用端依赖接口
abstract class CellBuilder {
    // 多态返回实际手机星系
    abstract CellPhone build();
    // 构建厂商
    abstract CellBuilder buildCompany(String name, String code, String mail);
    abstract CellBuilder buildColor(int red, int green, int blue);
    abstract CellBuilder buildNetwork(String ispName, String ispCode, String ispMail, String type);
    abstract CellBuilder buildWeight(int weight);
    abstract CellBuilder buildPrice(double price);
}

// 设置华为手机的默认属性
class HuaWeiCellPhoneBuilder extends CellBuilder{
    // 生成器需要与实际产品进行绑定-多态
    private CellPhone cellPhone = new HuaWeiCellPhone();
    @Override
    CellPhone build() {
        return cellPhone;
    }

    @Override
    CellBuilder buildCompany(String name, String code, String mail) {
        Company company = new Company(name, code, mail);
        cellPhone.setManufacturer(company);
        return this;
    }

    @Override
    CellBuilder buildColor(int red, int green, int blue) {
        cellPhone.setColor(new Color(red, green, blue));
        return this;
    }

    @Override
    CellBuilder buildNetwork(String ispName, String ispCode, String ispMail, String type) {
        cellPhone.setNetworkType(new NetworkType(new Company(ispName, ispCode, ispMail), type));
        return this;
    }

    @Override
    CellBuilder buildWeight(int weight) {
        cellPhone.setWeight(weight);
        return this;
    }

    @Override
    CellBuilder buildPrice(double price) {
        cellPhone.setPrice(price);
        return this;
    }
}
// 构建器
class HonorCellPhoneDirect {
    CellBuilder cellBuilder = null;
    public HonorCellPhoneDirect(CellBuilder builder) {
        this.cellBuilder = builder;
    }
    public void construct(String ipsName, String netWorkType) {
        // 作为华为手机的生成器,通过填充默认值的形式,来初始化华为手机
        cellBuilder.buildNetwork(ipsName, "100010", "mail.100010.cn", netWorkType)
                .buildCompany("honor", "12000", "mail.honor.huawei.com")
                .buildPrice(6666.66)
                .buildWeight(10);
    }
}

常用生成器模型

  1. 简单类图

在这里插入图片描述
2. 实现

实际使用生成器模式,往往省掉 Director而直接由Builderbuild实际需要产品对象,当然这取决于实际的业务场景。如果使用Direct时那么就可以构建FtpDirector等等模板,来实现简单传参和解构。

/** 使用生成器+单例模式构建url
 * @Author: Shiraki
 * @Date: 2020/9/17 20:24
 */
public class UrlBuilder {
    private String protocol = "http";
    private String host = "127.0.0.1";
    private Integer port = 80;
    private Map<String, String> params = null;
    private String userName = "admin";
    private String passWord = "123456";
    private String path = "/index";
    static private String paramDiv = "&";

    // 阻止new
    private UrlBuilder() {
    }

    public static UrlBuilder create() {
        return new UrlBuilder();
    }

    public UrlBuilder buildProtocol(String protocol) {
        this.protocol = protocol;
        return this;
    }

    public UrlBuilder buildHost(String hostName) {
        this.host = hostName;
        return this;
    }

    public UrlBuilder buildPath(String path) {
        this.path = path;
        return this;
    }

    public UrlBuilder buildPort(Integer port) {
        this.port = port;
        return this;
    }

    public UrlBuilder buildPassWord(String passWord) {
        try {
            this.passWord = URLEncoder.encode(passWord, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return this;
    }

    public UrlBuilder builderParams(Map<String, String> params) {
        this.params = params;
        return this;
    }

    public String build() {
        StringBuilder url = new StringBuilder();
        url.append(protocol)
                .append("://")
                .append(userName).append(":")
                .append(passWord).append("@")
                .append(host).append(":").append(port)
                .append(path);
        if (null != params) {
            this.params.forEach((k, v) -> url.append(k).append("=").append(v).append(paramDiv));
        }
        return url.substring(0, url.length() - 1);
    }

    public static void main(String[] args) {
        // 单例创建构造器
        UrlBuilder builder = UrlBuilder.create();
        // 构建参数
        builder.builderParams(Stream.of("key1", "key2").collect(Collectors.toMap(String::toString, String::toUpperCase)));
        // 打印构建结果
        System.out.println("builder.build() = " + builder.build());
    }
}

总结

生成器的模型里编程实现的时候往往采用的是链式编程的编码方式。但是使用链式编程并不一定是生成器模型,链式编程只是一个便捷的手段。生成器模型也经常省略Direct

优点:

  • 能够隐藏对象内部修改,因为使用生成器模式的时候只需要关注生成器的接口,无需关注实际对象的构造方法,同时与生成器关联的实现解耦。
  • 提供对创建对象的精细控制,通俗一点说就是你可以一步一步填写或者选择对象的属性,当对象的属性满足你的需求后最后返回对象。

缺点

  • 一个构建器只能对应一个产品,其实也不是缺点,因为生成器模式本身也不是用来适配多个产品的方式,是对单一复杂对象构建。如果要构建多个不同类型的对象,那么可以选择抽象工厂模式。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值