从零开始学设计模式(四)—建造者模式(Builder Pattern)

简介: 建造者模式(Builder Pattern)建造者模式使用多个简单的对象一步一步构建成一个复杂的对象,这种类型的设计模式也属于创建型模式,它提供了一种创建对象的最佳方式。

建造者模式(Builder Pattern)

建造者模式使用多个简单的对象一步一步构建成一个复杂的对象,这种类型的设计模式也属于创建型模式,它提供了一种创建对象的最佳方式。

一个Builder 类会一步一步构造最终的对象。该Builder 类是独立于其他对象的

难度系统:中级
提出者:Gang Of Four

意图

将复杂对象的构造与其表示分离,以便相同的构造过程可以创建不同的表示

主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

何时使用:一些基本部件不会变,而其组合经常变化的时候。

如何解决:将变与不变分离开。

关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

解释

现实世界的例子

想象一个角色扮演游戏的角色生成器。最简单的选择是让电脑为你创建角色。但是如果你想选择角色细节,如职业、性别、发色等。当你所有选择一步一步都选定好时,角色生成器也就逐步生成了一个角色,这一过程就是建造者模式创建对象的过程

简而言之

允许你创建不同风格的对象,同时避免构造函数污染。当一个对象可能有多种风格时很有用。或者当创建对象涉及很多步骤时

维基百科说

The builder pattern is an object creation software design pattern with the intentions of finding a solution to the telescoping constructor anti-pattern(建造者模式是一种对象创建软件设计模式,旨在找到伸缩构造器反模式的解决方案)

说到这里,让我补充一下伸缩构造函数反模式是什么。在这一点或其他方面,我们可能都见过类似下面这样的构造函数

public Hero(Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon) {
}

正如你可以看到的未来那样,这个构造函数参数的数量会很快失控,并且很难理解参数的排列顺序和组合。此外,如果你在未来增加更多选项,这个参数列表可能会继续增长。这称为伸缩构造函数反模式

程序代码示例

上面的N参数构造函数示例,明智的选择是使用建造者模式。首先,我们有我们想要创造的英雄

public final class Hero {
  private final Profession profession;
  private final String name;
  private final HairType hairType;
  private final HairColor hairColor;
  private final Armor armor;
  private final Weapon weapon;

  private Hero(Builder builder) {
    this.profession = builder.profession;
    this.name = builder.name;
    this.hairColor = builder.hairColor;
    this.hairType = builder.hairType;
    this.weapon = builder.weapon;
    this.armor = builder.armor;
  }
}

然后我们设计建造者

public static class Builder {
    private final Profession profession;
    private final String name;
    private HairType hairType;
    private HairColor hairColor;
    private Armor armor;
    private Weapon weapon;

    public Builder(Profession profession, String name) {
      if (profession == null || name == null) {
        throw new IllegalArgumentException("profession and name can not be null");
      }
      this.profession = profession;
      this.name = name;
    }

    public Builder withHairType(HairType hairType) {
      this.hairType = hairType;
      return this;
    }

    public Builder withHairColor(HairColor hairColor) {
      this.hairColor = hairColor;
      return this;
    }

    public Builder withArmor(Armor armor) {
      this.armor = armor;
      return this;
    }

    public Builder withWeapon(Weapon weapon) {
      this.weapon = weapon;
      return this;
    }

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

最后我们可以这样来建造Hero:

Hero mage = new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER).build();

应用场景

当遇到如下的情况你应该考虑使用建造者模式:

  • 创建复杂对象的算法应该独立于组成对象的部件以及它们是如何组装的
  • 构建过程必须允许对构建的对象进行不同的表示

Java中的现实例子

优缺点

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

写在最后

建造者模式又称之为生成器模式,一般来说有三个角色:建造者、具体的建造者、监工角色,为了形象的说明这三个角色的结构和定义我们自己来设计一个程序实例。

我们假设要制作一份宣传文案,一份文案可以包含一个或多个文档,文档有三种类型:文字文档、图表文档、图片文档。根据不同类型文档的组合我们有不同类型的文案生成,如文字文案由纯文字文档组成,图表文案由图表文档和图片文档组成,混合文案由文字文档、图表文档、图片文档三者共同组成。

不同类型的文档由不同的书写工具书写,如文字文档由MicrosoftWord工具编写,图表文档由MicrosoftExcel工具编写,图片文档由PhotoShop工具编写。

按照上面的假设需求,我们首先设计程序类图如下:


img_7db491b75cda0879468cf2cee2acb40b.png
image.png

接下来编写程序
步骤一:创建文档接口和编写工具接口

public interface Document {

    /**
     *
     * @return 文档名称
     */
    String name();

    /**
     *
     * @return 文档类型
     */
    String type();

    /**
     *
     * @return 书写工具
     */
    WriteTool writeTool();
}
public interface WriteTool {

    /**
     *
     * @return 返回书写工具[名称]+"write"
     */
    String write();
}

步骤二:编写WriteTool接口的实现类

public class MicrosoftWord implements WriteTool{
    @Override
    public String write() {
        return "MicrosoftWord write";
    }
}

public class MicrosoftExcel implements WriteTool {
    @Override
    public String write() {
        return "MicrosoftExcel write";
    }
}
public class PhotoShop implements WriteTool{
    @Override
    public String write() {
        return "PhotoShop write";
    }
}

步骤三:编写Document接口的实现类

public class Chart implements Document {
    @Override
    public String name() {
        return "chart document";
    }

    @Override
    public String type() {
        return "table";
    }

    @Override
    public WriteTool writeTool() {
        return new MicrosoftExcel();
    }
}

public class Image implements Document {
    @Override
    public String name() {
        return "image document";
    }

    @Override
    public String type() {
        return "image";
    }

    @Override
    public WriteTool writeTool() {
        return new PhotoShop();
    }
}

public class Word  implements Document{
    @Override
    public String name() {
        return "word document";
    }

    @Override
    public String type() {
        return "text";
    }

    @Override
    public WriteTool writeTool() {
        return new MicrosoftWord();
    }
}

步骤四:编写建造者CopyWriter类

/**
 * 不同的文案包含一些不同类型的文档
 * 定义建造对象的方式方法
 */
public class CopyWriter {

    //包含的文档
    private  List<Document> documents = new ArrayList<>();

    //名字
    private String name;

    //文案类型  文字 图表 混合
    private String type;


    public CopyWriter(String name,String type){

        this.name = name;
        this.type = type;
    }

    //添加文档
    public CopyWriter addDocument(Document document) {

        if (null == document){
            throw new IllegalArgumentException("documnet can not be null");
        }
        this.documents.add(document);
        return this;
    }

    public String name(){
        return this.name;
    }

    public String getType(){
        return this.type;
    }
    //展示文案包含的文档信息
    public void showDocuments(){

        for (Document doc:documents)
        {
              System.out.print("name:"+doc.name());
              System.out.print(" type:"+doc.type());
              System.out.println(" writeTool:"+doc.writeTool().write());
        }
    }

}

步骤五:编写监工CopyWriterBuilder

//将一个复杂对象的构建过程与其表示相分离
public class CopyWriterBuilder {

    /**
     * 准备文本类型的文案
     * @return
     */
    public CopyWriter prepareTextCopyWriter(){

        CopyWriter copyWriter = new CopyWriter("TextCopyWriter","text");

        //文本类型的文案只需要准备文字文档即可
        copyWriter.addDocument(new Word());

        return copyWriter;
    }

    /**
     * 准备图表类型的文案
     * @return
     */
    public CopyWriter prepareTableCopyWriter(){

        CopyWriter copyWriter = new CopyWriter("TableCopyWriter","table");

        //图表类型的文案需要准备图表文档和图片文档
        copyWriter.addDocument(new Chart()).addDocument(new Image());
        return copyWriter;
    }

    /**
     * 准备混合类型的文案 包含文本和图表
     * @return
     */
    public CopyWriter prepareMixCopyWriter(){

        CopyWriter copyWriter = new CopyWriter("MixCopyWriter","Mix");

        //图表类型的文案需要准备图表文档、图片文档、文字文档
        copyWriter.addDocument(new Chart()).addDocument(new Image()).addDocument(new Word());
        return copyWriter;
    }

}

步骤六:最后编写使用者

public class App {

    public static void main(String[] args){

        CopyWriterBuilder builder = new CopyWriterBuilder();

        CopyWriter txtCopyWriter = builder.prepareTextCopyWriter();
        System.out.println(txtCopyWriter.name());
        txtCopyWriter.showDocuments();
        System.out.println("---------------------------------");
        CopyWriter tableCopyWriter = builder.prepareTableCopyWriter();
        System.out.println(tableCopyWriter.name());
        tableCopyWriter.showDocuments();
        System.out.println("---------------------------------");
        CopyWriter mixCopyWriter = builder.prepareMixCopyWriter();
        System.out.println(mixCopyWriter.name());
        mixCopyWriter.showDocuments();

    }

}

运行App输出结果如下:

TextCopyWriter
name:word document type:text writeTool:MicrosoftWord write
---------------------------------
TableCopyWriter
name:chart document type:table writeTool:MicrosoftExcel write
name:image document type:image writeTool:PhotoShop write
---------------------------------
MixCopyWriter
name:chart document type:table writeTool:MicrosoftExcel write
name:image document type:image writeTool:PhotoShop write
name:word document type:text writeTool:MicrosoftWord write

下一章节我将介绍原型模式(Prototype Pattern)这将是最后一个创建型模式

码字不易,各位看官如果喜欢的话,请给点个喜欢️,关注下我。我将努力持续不断的为大家更新完此系列

目录
相关文章
|
3月前
|
设计模式 算法
设计模式--建造者模式 builder
这篇文章通过一个电脑购买的例子,详细解释了建造者模式的四个角色(产品类、抽象构建者、实体构建类和指导者类),并提供了相应的代码实现,阐述了建造者模式在设计复杂对象时的应用和优势。
设计模式--建造者模式 builder
|
17天前
|
设计模式 JavaScript Java
Java设计模式:建造者模式详解
建造者模式是一种创建型设计模式,通过将复杂对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。本文详细介绍了建造者模式的原理、背景、应用场景及实际Demo,帮助读者更好地理解和应用这一模式。
|
3月前
|
设计模式
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
这篇文章详细解释了工厂模式,包括简单工厂、工厂方法和抽象工厂三种类型。每种模式都通过代码示例展示了其应用场景和实现方法,并比较了它们之间的差异。简单工厂模式通过一个工厂类来创建各种产品;工厂方法模式通过定义一个创建对象的接口,由子类决定实例化哪个类;抽象工厂模式提供一个创建相关或依赖对象家族的接口,而不需要明确指定具体类。
设计模式-工厂模式 Factory Pattern(简单工厂、工厂方法、抽象工厂)
|
3月前
|
设计模式 算法 Java
Java设计模式-建造者模式(6)
Java设计模式-建造者模式(6)
|
3月前
|
设计模式 Java
设计模式--适配器模式 Adapter Pattern
这篇文章介绍了适配器模式,包括其基本介绍、工作原理以及类适配器模式、对象适配器模式和接口适配器模式三种实现方式。
|
4月前
|
设计模式 XML 存储
【四】设计模式~~~创建型模式~~~建造者模式(Java)
文章详细介绍了建造者模式(Builder Pattern),这是一种创建型设计模式,用于将复杂对象的构建与其表示分离,允许分步骤创建一个复杂的对象而无需指定其内部的具体构造细节。通过定义抽象建造者、具体建造者、指挥者和产品角色,建造者模式允许通过相同的构建过程创建不同的产品表示,提高了系统的灵活性和扩展性。
|
5月前
|
设计模式 JavaScript
js设计模式【详解】—— 建造者模式
js设计模式【详解】—— 建造者模式
57 0
|
6月前
|
设计模式
设计模式-05建造者模式(Builder Pattern)
设计模式-05建造者模式(Builder Pattern)
|
26天前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
3月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。