设计模式——建造者模式

embedded/2024/12/23 20:29:11/

设计模式——建造者模式

目录

介绍

建造者模式(Builder Pattern)是一种创建型设计模式,它通过将一个复杂对象的构建过程分解成多个简单的步骤,从而使得不同的构建过程可以生成不同的表现形式。建造者模式的关键思想是使用相同的构建步骤来创建不同的对象表示,它适用于构建过程需要多个步骤并且可能有多个不同表现形式的场景。

实现

结构及工作流程

建造者模式的结构

建造者模式通常涉及以下几个角色:

  1. 产品(Product):最终构建出来的复杂对象,通常是由多个部分组成。
  2. 抽象建造者(Builder):声明了构建产品各个部分的抽象方法,通常提供一个 build() 方法来构建完整的对象。
  3. 具体建造者(ConcreteBuilder):实现了抽象建造者中定义的构建方法,完成对各个部件的具体构建工作,最终生成产品。
  4. 指挥者(Director):负责控制建造过程,它使用建造者来构建产品。指挥者与具体建造者进行交互,指定构建的顺序与步骤,最终生成一个完整的产品。
  5. 客户端(Client):客户端通过指挥者来执行建造过程,而不直接与具体建造者打交道。

建造者模式的工作流程

  1. 创建具体建造者:具体建造者实现了产品的具体构建步骤。
  2. 指挥者负责构建过程:指挥者使用具体建造者来按照预定的顺序构建产品。
  3. 客户端获取产品:客户端最终获取由建造者构建完成的产品对象。

经典实现

示例

示例代码:

  1. 产品类

    java">public class Product {private String partA;private String partB;private String partC;// Getters and setterspublic String getPartA() {return partA;}public void setPartA(String partA) {this.partA = partA;}public String getPartB() {return partB;}public void setPartB(String partB) {this.partB = partB;}public String getPartC() {return partC;}public void setPartC(String partC) {this.partC = partC;}@Overridepublic String toString() {return "Product [partA=" + partA + ", partB=" + partB + ", partC=" + partC + "]";}
    }
    
  2. 抽象建造者

    java">public abstract class Builder {protected Product product = new Product();public abstract void buildPartA();public abstract void buildPartB();public abstract void buildPartC();public Product getResult() {return product;}
    }
    
  3. 具体建造者

    java">public class ConcreteBuilder extends Builder {@Overridepublic void buildPartA() {product.setPartA("PartA is built");}@Overridepublic void buildPartB() {product.setPartB("PartB is built");}@Overridepublic void buildPartC() {product.setPartC("PartC is built");}
    }
    
  4. 指挥者

    java">public class Director {private Builder builder;public Director(Builder builder) {this.builder = builder;}// 指挥者控制构建过程public void construct() {builder.buildPartA();builder.buildPartB();builder.buildPartC();}
    }
    
  5. 测试代码(客户端)

    java">public class Client {public static void main(String[] args) {Builder builder = new ConcreteBuilder();Director director = new Director(builder);director.construct();Product product = builder.getResult();System.out.println(product);}
    }
    

以上述为例,在测试代码中,我们只需要将指挥者和具体建造者都创建后,便可轻松获取产品实例。指挥者调控具体建造者,将产品的各个部分进行组装,最终组装出产品对象。
在指挥者的 construct() 方法中,我们也可以将返回值改为具体对象 Product ,这样指挥者调用construct()后,可直接获取产品实例(可能这样做有些画蛇添足了,不过看起来可能会更加快速获取产品实例)

优缺点

优点

  1. 清晰的分工建造者模式将对象的构建过程分为多个独立的步骤,每个步骤由不同的建造者类负责,使得代码的组织更加清晰。
  2. 复杂对象的构建:可以灵活地处理一些复杂对象的构建,尤其适用于需要多个步骤来创建一个对象的场景。
  3. 可以灵活控制构建过程:由于指挥者类控制了构建的步骤,可以更方便地进行定制和修改构建过程。
  4. 减少代码重复:构建过程中的重复代码被集中到建造者中,客户端不需要直接与构建过程打交道。

缺点

  1. 增加了类的数量建造者模式需要多个类来完成不同的建造步骤,这会导致类的数量增加,可能会增加系统的复杂度。
  2. 适用于产品变化较小的情况建造者模式适用于同一个产品的不同表现形式的构建,如果产品的构建方式变化非常大,使用建造者模式可能不太合适。
使用场景

建造者模式适用于以下几种情况:

  1. 构建复杂对象:当构建一个复杂对象时,它通常需要多个部件,而这些部件的构建步骤可以被分离到不同的类中
  2. 构建过程需要多个步骤:如果一个对象的构建过程涉及到多个不同的步骤,但这些步骤之间可以相互独立或顺序执行,那么建造者模式很适合
  3. 需要灵活的产品生成:当同一个产品有多种表现形式,且这些表现形式可能有不同的构建过程时,建造者模式允许灵活控制构建过程

扩展实现

建造者模式除了上面的用途外,在开发中还有一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果创建这个类的实例,代码可读性会非常差,而且很容易引入错误,此时就可以利用建造者模式进行重构。

示例

示例代码:

java">public class Phone {private String cpu;private String screen;private String memory;private String mainboard;private Phone(Builder builder) {cpu = builder.cpu;screen = builder.screen;memory = builder.memory;mainboard = builder.mainboard;}public static final class Builder {private String cpu;private String screen;private String memory;private String mainboard;public Builder() {}public Builder cpu(String val) {cpu = val;return this;}public Builder screen(String val) {screen = val;return this;}public Builder memory(String val) {memory = val;return this;}public Builder mainboard(String val) {mainboard = val;return this;}public Phone build() {return new Phone(this);}}@Overridepublic String toString() {return "Phone{" +"cpu='" + cpu + '\'' +", screen='" + screen + '\'' +", memory='" + memory + '\'' +", mainboard='" + mainboard + '\'' +'}';}
}

测试代码(客户端)

java">public class Client {public static void main(String[] args) {Phone phone = new Phone.Builder().cpu("intel").mainboard("华硕").memory("金士顿").screen("三星").build();System.out.println(phone);}
}

通过这种设计,我们可以很轻松的实例化出自己想要的对象。不难发现,这种实例化对象是通过链式编程来实现的,我们在开发时,有时用到的第三方库中,也会有这种实例化对象的方式。对于成员变量过多的类,使用这种方式来获取实例会更加方便些。

总结

建造者模式通过将复杂对象的构建过程分离成多个步骤,使得客户端可以通过不同的建造者来构建出不同的对象。它非常适用于那些构建过程需要多个步骤的复杂对象,能够有效地提高系统的灵活性和可维护性。但它也可能增加类的数量,增加系统的复杂度,因此在选择时需要考虑对象构建的复杂性


http://www.ppmy.cn/embedded/148161.html

相关文章

如何深入学习JVM底层原理?

前言 对于Java虚拟机(JVM),我相信大多数人的学习模式都是在面试前夕才会临时抱佛脚,而在平时的工作中,对它的关注可能就略显冷淡了。我敢打赌,很多人的书架上,《深入理解Java虚拟机》第三版恐怕…

Chapter 3-1. Detecting Congestion in Fibre Channel Fabrics

Chapter 3. Detecting Congestion in Fibre Channel Fabrics This chapter covers the following topics: 本章包括以下主题: Congestion detection workflow. Congestion detection metrics. Congestion detection metrics and commands on Cisco MDS switches. Automatic A…

画图,matlab,

clear;close all;clc;tic;dirOutput dir(*.dat); % 罗列所有后缀-1.dat的文件列表,罗列BDDATA的数据 filenames string({dirOutput.name}); % 提取文件名%% 丢包统计 FILENAMES [""]; LOSS_YTJ [ ]; LOSS_RAD [ ]; LOSS_ETH [ ]…

mybatis是咋干活的

# 为啥写这篇文章呢 就是为了帮助那些像我一样比较笨但是一直努力的人,从一个笨人的角度去写一篇通俗易懂的文章打通spring和mysql之间的关系,另外mybatis作为承上启下的节点其重要性可想而知。 谈整合之前你真的掌握了mybatis么 首先上一段mybatis独…

[Shader] 【图形渲染】【Unity Shader】Shader数学基础1-笛卡儿坐标系的应用

在Shader编程中,矢量和矩阵是常用的数学工具,而笛卡儿坐标系是其中的基础。理解笛卡儿坐标系,特别是在不同图形API(如OpenGL与DirectX)中的差异,对于开发者来说至关重要。本篇文章将介绍笛卡儿坐标系的基本概念及其在Shader中的应用,帮助你理解如何在不同坐标系间进行转…

QT多媒体开发(二):播放音频

简介 QMediaPlayer 可以用于播放经过压缩的音频文件,如 MP3 文件和 WMA 文件。QSoundEffect 可以 用于播放低延迟音效文件,例如无压缩的 WAV 文件。这两个类都可以用于播放本地文件和网络文件。 QMediaPlayer 与播放音频相关的接口函数如下&#xff1a…

如何利用Python爬虫获得1688按关键字搜索商品

在当今的数字化时代,数据已成为企业竞争的核心资源。对于电商行业来说,了解市场动态、分析竞争对手、获取商品信息是至关重要的。Python作为一种强大的编程语言,其丰富的库和框架使得数据爬取变得简单易行。本文将介绍如何使用Python爬虫技术…

基于Linux编写C语言基础命令

目录 一、常用的Linux命令 1、改变及显示目录命令:cd、pwd、ls。 1.1、cd(Change Directory) 1.2、pwd(Print Working Directory) 1.3、ls(List) 2、文件及目录的创建、复制、删除和移动命…