创建型设计模式 - 建造者设计模式 - JAVA

举报
神的孩子在歌唱 发表于 2024/06/30 23:46:45 2024/06/30
【摘要】 @TOC前言 这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。 作者:神的孩子都在歌唱一. 简介以下是百度百科 对建造者模式的解释 : 文章地址建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。解决问题 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。 当构造过程必须允许被构造的对象有不同表示...

@TOC

前言 这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。 作者:神的孩子都在歌唱

一. 简介

以下是百度百科 对建造者模式的解释 : 文章地址

建造者模式是设计模式的一种,将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

  1. 解决问题

    • 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。

    • 当构造过程必须允许被构造的对象有不同表示时。

  2. 在这样的设计模式中,有以下几个角色:

    • builder:为创建一个产品对象的各个部件指定抽象接口。

    • ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件,定义并明确它所创建的表示,并提供一个检索产品的接口。

    • Director:构造一个使用Builder接口的对象。

    • Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口


img


个人理解:建造者模式就是将一大堆东西抽象出来,然后将这些东西拼接成一个不一样的东西(把这当成组装更好理解)


二. 使用场景分析

温馨提示:以下场景分析是我看了几篇建造者模式的文章,然后以自己的理解去编写代码案例总结下来的结论,如果有理解不对的地方或者可以补充的地方请指出

以下是我工厂模式文章举的例子:


image-20231224211149766

这个工厂 可以通过指定磁盘内存 两个参数 去创建一台电脑computer的对象,可是我想在加上一个是否使用喇叭 isSpeaker 的参数 ,有些电脑需要喇叭,有些不需要,所以这个参数不是必须填的了,可是在之前的工厂中,你想创建一台电脑,你就必须要输入指定的参数才可以,可能有很多人说不需要speaker 就输入null就可以了,可是如果这种类似的参数很多呢,要一个个输入null吗?显然是不行的。并且memory和disk是必须输入的参数,这种参数能否和isSpeaker这种可选的参数区分开,方便管理呢?这时候就需要建造者模式去解决这种问题了。


总结上面我个人思考的观点:建造者模式的引入是为了解决工厂和抽象工厂设计模式在对象包含大量属性时的一些问题。当对象包含大量属性时,工厂和抽象工厂设计模式存在三个主要问题。

  1. 从客户端程序传递到 Factory 类的参数太多,这很容易出错,因为大多数时候,参数的类型是相同的,并且从客户端很难维护参数的顺序。

  2. 有些参数可能是可选的,但在工厂模式中,我们被迫发送所有参数,并且可选参数需要作为 NULL 发送。

我们可以通过提供带有必需参数的构造函数,然后提供不同的 setter 方法来设置可选参数来解决参数过多的问题。这种方法的问题是,代码可读性会非常差,而且很容易引入错误。 构建器模式通过提供一种 逐步构建对象的方法 来解决这些的问题。


三. 代码案例

看这个案例前可以先去看看我的写的这篇工厂模式文章,我是根据里面的案例进行优化的


当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,比如以下代码,创建一台没有喇叭 的pc电脑,就要在后面输入null,而且这个参数是必须要输入的

        Computer pc = ComputerFactory.getComputer("pc", "17 GB", "1 TB",null);


可以通过建造者模式优化以上问题,我设计了如下示意图:

image-20240226230811065

让我们看看如何在 这个案例 中实现建造者设计模式解决问题。

3.1 创建ComputerBuilder 类

这个类是通过建造者模式去设计的,我们可以通过这个类去构造computer对象

/**
 * 电脑对象
 *
 * @author chenyunzhi
 * @date 2024/2/25 21:49
 */
public class ComputerBuilder extends Computer{
​
    private final String memory;
​
    private final String disk;
​
    private final Boolean isSpeaker;
​
    /**
     * 私有构造函数 以 Builder 类作为参数
     */
    private ComputerBuilder(Builder builder) {
        this.memory = builder.memory;
        this.disk = builder.disk;
        this.isSpeaker = builder.isSpeaker;
    }
​
    public static class Builder {
        private final String memory;
        private final String disk;
        private Boolean isSpeaker;
​
        public Builder(String memory, String disk) {
            this.memory = memory;
​
            this.disk = disk;
        }
        public Builder setIsSpeaker(Boolean isSpeaker) {
            this.isSpeaker = isSpeaker;
            return this;
        }
        /**
         * 返回客户端程序所需的对象
         */
        public Computer build() {
            return new ComputerBuilder(this);
        }
    }
    
    @Override
    public String memory() {
        return this.memory;
    }
​
    @Override
    public String disk() {
        return this.disk;
    }
​
    @Override
    public Boolean isSpeaker() {
        return this.isSpeaker;
    }
}
​

代码解析:

  1. 首先,我们需要创建一个 ComputerBuilder 类 ,里面有Computer 的所有参数,然后在 ComputerBuilder 类 中创建一个 静态嵌套类 Builder ,然后将所有参数从外部类复制到 Builder 类

  2. 在 Builder 类中创建一个 公共的 构造函数,并将所有必需的属性作为参数。

  3. 在Builder 类 中 设置可选参数 isSpeaker 的方法,并且在设置可选属性后应该返回相同的 Builder 对象。

  4. 最后一步是在 Builder 类中提供一个build()方法,该方法将返回客户端程序所需的对象。为此,我们需要在类中有一个私有构造函数,并以 Builder 类作为参数。

3.2 修改子类

之前我们是通过传入指定参数方式,现在修改成 传入Computer 对象

public class Laptop extends Computer {
    
    private final String memory;
    private final  String disk;
    private  Boolean isSpeaker;
​
    public Laptop(Computer computer) {
        this.memory = computer.memory();
        this.disk = computer.disk();
        this.isSpeaker = computer.isSpeaker();
    }
    
    @Override
    public String memory() {
        return this.memory;
    }
​
    @Override
    public String disk() {
        return this.disk;
    }
​
    @Override
    public Boolean isSpeaker() {
        return this.isSpeaker;
    }
}

pc

public class Pc extends Computer {
​
    private final String memory;
    private final String disk;
    private Boolean isSpeaker;
    
    public Pc(Computer computer) {
        this.memory = computer.memory();
        this.disk = computer.disk();
        this.isSpeaker = computer.isSpeaker();
    }
​
    @Override
    public String memory() {
        return this.memory;
    }
​
    @Override
    public String disk() {
        return this.disk;
    }
​
    @Override
    public Boolean isSpeaker() {
        return this.isSpeaker;
    }
}


3.3 修改工厂

ComputerFactory

    public static Computer getComputer(String type, Computer computer) {
        if (PC.equals(type)) {
            return new Laptop(computer);
        } else if (LAPTOP.equals(type)) {
            return new Pc(computer);
        } else {
            return null;
        }
    }


3.4 测试

public class Test
{
    public static void main(String[] args) {
        Computer laptop = ComputerFactory.getComputer("laptop",
                new ComputerBuilder.Builder("17 GB", "1TB").setIsSpeaker(true).build());
​
        Computer pc = ComputerFactory.getComputer("pc",
                new ComputerBuilder.Builder("17 GB", "1TB").build());
​
        System.out.println("pc电脑 = " + pc);
​
        System.out.printf("laptop电脑 = " + laptop);
​
    }
}


image-20240226234638623

四. 建造者模式案例

Java 类中的一些构建器模式示例是:

  • java.lang.StringBuilder#append()(不同步)

  • java.lang.StringBuffer#append() (同步)

通过调用append方法,我们可以逐步构建字符串,最终通过toString方法获得最终的表示。

这就是 java 中构建器设计模式的全部内容。


作者:神的孩子都在歌唱 本人博客:https://blog.csdn.net/weixin_46654114 转载说明:务必注明来源,附带本人博客连接。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。