【设计模式】Python 设计模式之建造者模式(Builder Pattern)详解

Python 设计模式之建造者模式(Builder Pattern)详解

在软件开发中,创建复杂对象往往需要多个步骤,而这些步骤之间的顺序、配置可能有多种变化。为了解决这个问题,建造者模式(Builder Pattern)应运而生。它可以将对象的构建过程与对象的表示分离,使得同样的构建过程可以创建不同的表示。

本文将详细介绍Python中的建造者模式,探讨其原理、适用场景、具体实现方式及优化方向,帮助开发者更好地理解和运用这一设计模式。

什么是建造者模式?

建造者模式是一种创建型设计模式,用于将一个复杂对象的构建过程分解为多个步骤,并通过一个**指挥者(Director)**来按照这些步骤来构造对象。建造者模式的核心思想是将对象的构造与对象的表示(如何创建对象)分离开来,使得同样的构建过程可以生成不同类型或配置的对象。

建造者模式的角色

建造者模式主要包括以下四个角色:

  1. 产品(Product):表示需要构建的复杂对象。
  2. 建造者(Builder):定义创建产品的抽象接口,包含构造产品不同部分的方法。
  3. 具体建造者(ConcreteBuilder):实现 Builder 接口,完成复杂对象各个部分的实际构造工作。
  4. 指挥者(Director):负责管理 Builder,按照顺序调用 Builder 中的方法来一步步构建产品对象。

建造者模式的应用场景

建造者模式适用于以下几种场景:

  1. 构建复杂对象:如果对象的构造步骤非常复杂(需要许多配置项),且构建过程中步骤固定但顺序不同或部分步骤可选,则适合用建造者模式。
  2. 隔离复杂对象的创建和使用:在某些情况下,我们希望隔离复杂对象的创建逻辑和使用逻辑,使用建造者模式可以让用户专注于如何使用对象,而不需要关心对象的构造过程。
  3. 多种配置对象:当一个类的实例具有不同的配置方式时,建造者模式可以帮助简化对象的创建。

典型的应用场景包括:构建复杂的UI界面、文档生成器、汽车生产、餐厅点餐系统等。

建造者模式的结构

建造者模式的基本结构可以用UML类图表示如下:

+-----------------+        +-------------------+
|     Director    | <----> |      Builder       |
+-----------------+        +-------------------+| build_part1()    || build_part2()    |+-------------------+|V+-------------------+| ConcreteBuilder   |+-------------------+| build_part1()     || build_part2()     |+-------------------+|V+-------------------+|      Product      |+-------------------+

在这个结构中,Director 负责指挥 Builder 进行产品的创建,Builder 定义了构建产品的各个步骤,而 ConcreteBuilder 则负责实现这些步骤并生成最终的产品。

Python 实现建造者模式

接下来,我们通过一个具体的例子来实现建造者模式。假设我们要构建一个复杂的对象——房子(House),房子由不同的部分组成,如地基、墙壁、屋顶等。不同的房子类型可能有不同的部件配置(比如豪宅和普通房子)。

1. 定义产品类(Product)

房子是我们需要构建的复杂对象,因此我们首先定义一个 House 类。

class House:def __init__(self):self.foundation = Noneself.structure = Noneself.roof = Noneself.interior = Nonedef __str__(self):return f"Foundation: {self.foundation}, Structure: {self.structure}, Roof: {self.roof}, Interior: {self.interior}"

2. 定义建造者接口(Builder)

接下来,定义 Builder 抽象类,它包含构建房子不同部分的抽象方法。

from abc import ABC, abstractmethodclass HouseBuilder(ABC):@abstractmethoddef build_foundation(self):pass@abstractmethoddef build_structure(self):pass@abstractmethoddef build_roof(self):pass@abstractmethoddef build_interior(self):pass@abstractmethoddef get_house(self):pass

3. 实现具体建造者类(ConcreteBuilder)

我们需要具体的建造者类来构建不同类型的房子。比如,下面是豪宅(MansionBuilder)和普通房子(StandardHouseBuilder)的实现:

class MansionBuilder(HouseBuilder):def __init__(self):self.house = House()def build_foundation(self):self.house.foundation = "Concrete, reinforced with steel"def build_structure(self):self.house.structure = "Steel and Glass"def build_roof(self):self.house.roof = "Solar panel roof"def build_interior(self):self.house.interior = "Luxury interior with marble floors"def get_house(self):return self.houseclass StandardHouseBuilder(HouseBuilder):def __init__(self):self.house = House()def build_foundation(self):self.house.foundation = "Concrete"def build_structure(self):self.house.structure = "Wood and brick"def build_roof(self):self.house.roof = "Shingle roof"def build_interior(self):self.house.interior = "Basic interior with wooden floors"def get_house(self):return self.house

4. 定义指挥者类(Director)

Director 类负责控制构建过程,它接受一个 Builder 对象,并调用构建步骤来生成最终的产品。

class HouseDirector:def __init__(self, builder):self.builder = builderdef construct_house(self):self.builder.build_foundation()self.builder.build_structure()self.builder.build_roof()self.builder.build_interior()return self.builder.get_house()

5. 测试建造者模式

接下来,创建 HouseDirector 并传入不同的 Builder 来构建不同的房子。

# 测试建造者模式
mansion_builder = MansionBuilder()
director = HouseDirector(mansion_builder)
mansion = director.construct_house()
print("Mansion:", mansion)standard_builder = StandardHouseBuilder()
director = HouseDirector(standard_builder)
standard_house = director.construct_house()
print("Standard House:", standard_house)

输出结果:

Mansion: Foundation: Concrete, reinforced with steel, Structure: Steel and Glass, Roof: Solar panel roof, Interior: Luxury interior with marble floors
Standard House: Foundation: Concrete, Structure: Wood and brick, Roof: Shingle roof, Interior: Basic interior with wooden floors

改进建造者模式:链式调用

我们可以对建造者模式进行改进,使得它支持链式调用,这样可以使代码更加简洁、流畅。

class FluentHouseBuilder:def __init__(self):self.house = House()def build_foundation(self, foundation):self.house.foundation = foundationreturn selfdef build_structure(self, structure):self.house.structure = structurereturn selfdef build_roof(self, roof):self.house.roof = roofreturn selfdef build_interior(self, interior):self.house.interior = interiorreturn selfdef get_house(self):return self.house

使用链式调用构建房子:

builder = FluentHouseBuilder()
house = (builder.build_foundation("Concrete").build_structure("Wood and brick").build_roof("Shingle roof").build_interior("Basic interior with wooden floors").get_house())print(house)

这种方式让构建过程更加简洁,特别是在构建过程中的步骤较多时,链式调用可以减少代码冗余。

总结

建造者模式是一种非常适合构建复杂对象的设计模式,尤其是在对象的创建步骤较多、且顺序或配置变化较大的情况下。本文通过定义产品、抽象建造者、具体建造者以及指挥者,详细介绍了如何在Python中实现建造者模式。

建造者模式的好处在于它能够将对象的创建过程与其表示分离,便于扩展和维护。同时,我们还展示了如何通过链式调用的方式优化建造者模式,使代码更加简洁和可读。

希望这篇博客能帮助你更好地理解建造者模式,并能够

灵活应用到实际项目中。如果你有任何问题或建议,欢迎在评论区讨论!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/57092.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

结构化系统分析,结构化系统设计(正片)

结构化分析方法&#xff1a;是面向数据流进行需求分析的方法&#xff0c;是用抽象模型的概念&#xff0c;按软件内部数据传递、变换的关系&#xff0c;自顶向下逐层分解&#xff0c;直到找到满足功能要求的所有可实现的软件为止。 数据流图&#xff08;DFD&#xff09;&#xf…

Linux系统:本机(物理主机)访问不了虚拟机中的apache服务问题的解决方案

学习目标&#xff1a; 提示&#xff1a;本文主要讲述-本机(物理主机)访问不了虚拟机中的apache服务情况下的解决方案 Linux系统&#xff1a;Ubuntu 23.04&#xff1b; 文中提到的“本机”&#xff1a;代表&#xff0c;宿主机&#xff0c;物理主机&#xff1b; 首先&#xff0c…

吴恩达深度学习笔记(7)

误差分析&#xff1a; 你运行一个算法代替人类计算&#xff0c;但是没有达到人类的效果&#xff0c;需要手动检查算法中的错误&#xff0c;对模型的一些部分做相应调整&#xff0c;才能更好地提升分类的精度。如果不加分析去做&#xff0c;可能几个月的努力对于提升精度并没有…

旋转花键材质及运用场景

旋转花键的材质有很多种&#xff0c;其材质选择是一个涉及多方面因素的重要决策&#xff0c;‌主要取决于应用场景的具体要求&#xff0c;包括设备的运行环境、负载大小、运行速度以及所需的耐磨性和耐腐蚀性等因素。 1、碳钢&#xff1a;价格低廉、具有较好的韧性和耐磨性&…

【分享】项目开发中的计算问题

事件背景 最近也就上个月吧&#xff0c;拿到一个新的需求&#xff0c;新建一个页面&#xff0c;三个Grid联动&#xff0c;涉及很多的页面和sql以及Java计算。 简略的画个表格表示一下&#xff1a; 第一个Grid&#xff1a; 第二个Grid&#xff1a; 第三个Grid&#xff1a; 业…

openKylin系统SSH服务配置结合cpolar轻松实现开放麒麟远程连接

前言 本文主要介绍如何在openKlyin系统中设置ssh连接&#xff0c;并结合cpolar内网穿透工具实现远程也可以ssh连接本地局域网内部署的openKlyin系统. openKylin是中国首个基于Linux 的桌面操作系统开发者平台&#xff0c;通过开放操作系统源代码的方式&#xff0c;打造具有自…

C#从零开始学习(继承)(6)

本章所有的代码都放在 https://github.com/hikinazimi/head-first-Csharp 使用冒号继承一个基类,子类扩展一个基类时,他会继承它的成员:也就是基类中的所有字段,属性和方法,他们会自动增加到子类 子类覆盖方法改变它继承的成员 基类中的方法增加virtual关键字子类同名方法增加…

滑动窗口经典例题

链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 来源&#xff1a;牛客网 题目描述 读入n&#xff0c;xn&#xff0c;xn&#xff0c;x,给出nnn个数a[1],a[2],……,a[n]a[1],a[2],……,a[n]a[1],a[2],……,a[n],求最小的区间[l,r][l,r][l,r]&#xff0c;使a[l]a[l1]……

Axure显示与隐藏——元件动作一

亲爱的小伙伴&#xff0c;在您浏览之前&#xff0c;烦请关注一下&#xff0c;在此深表感谢&#xff01; 课程主题&#xff1a;显示与隐藏 主要内容&#xff1a;显示/隐藏/切换三种效果&#xff0c;动画效果&#xff0c;更多效果 应用场景&#xff1a;元件自身状态变化、操作…

LinkedList作者:我虽然开发了LinkedList,但是我更爱用ArrayList

感谢Java面试教程关于LinkedList经验分享 PS冷知识&#xff1a;LinkedList的作者更爱使用ArrayList。 ArrayList 和 LinkedList 是 Java 中两种常见的 List 实现类&#xff0c;它们在底层数据结构、性能特征和使用场景上有显著的区别。 底层数据结构&#xff1a; ArrayList …

Flux.never 使用说明书

public static <T> Flux<T> never()Create a Flux that will never signal any data, error or completion signal. 创建一个永远不会发出任何数据、错误或完成信号的 Flux。 Type Parameters: T - the Subscriber type target Returns: a never completing Flu…

深度学习 自动求梯度

代码示例&#xff1a; import torch# 创建一个标量张量 x&#xff0c;并启用梯度计算 x torch.tensor(3.0, requires_gradTrue)# 计算 y x^2 y torch.pow(x, 2)# 判断 x 和 y 是否需要梯度计算 print(x.requires_grad) # 输出 x 的 requires_grad 属性 print(y.requires_g…

软件缺陷报告

软件缺陷报告样例 软件缺陷基本内容 标题&#xff1a;一句话概述缺陷预置条件&#xff1a;缺陷的前提条件重现步骤&#xff1a;缺陷出现步骤期望结果&#xff1a;没有出现缺陷应该的结果实际结果&#xff1a;缺陷结果 软件缺陷的状态 新建&#xff08;激活&#xff09;->…

Lua中的break语句

软考鸭微信小程序 过软考,来软考鸭! 提供软考免费软考讲解视频、题库、软考试题、软考模考、软考查分、软考咨询等服务 在Lua编程语言中&#xff0c;break语句是一种控制流语句&#xff0c;用于在循环中提前终止循环的执行。无论是while循环、repeat-until循环还是for循环&…

idea2024启动Java项目报Error running CloudPlApplication. Command line is too long.

idea2024启动Java项目报Error running CloudPlApplication. Command line is too long. 解决方案&#xff1a; 1、打开Edit Configurations 2、点击Modify options设置&#xff0c;勾选Shorten command line 3、在Edit Configurations界面下方新增的Shorten command line选项中…

前海一个很偏僻的路边免费停车点

​这个偏僻的路边免费停车点具体位置在前海金融中心大厦附近的中国中铁门口&#xff0c;大概有可以停30~50个位置的样子。缺点是很多灰尘哈。第一次路过的时候&#xff0c;我还以为很多车在等红绿灯&#xff0c;靠近才发现&#xff0c;这些车只是停在路面上。其中要想知道看车子…

MySQL | Explain的是使用详解

介绍 Explain是SQL分析工具中非常重要的一个功能&#xff0c;可以模拟优化器执行查询语句&#xff0c;帮助我们理解查询是如何执行的&#xff1b;分析查询执行计划可以帮助我们发现sql查询瓶颈&#xff0c;优化查询性能。 使用方法 MySQL5.7 版本之前使用&#xff1a; Expl…

解决 Elasticsearch cluster_block_exception 错误的终极指南

Elasticsearch 是一个功能强大的分布式搜索引擎&#xff0c;广泛应用于全文检索、实时分析等场景。 尽管如此&#xff0c;像任何复杂系统一样&#xff0c;它也会遇到一些运行问题&#xff0c;其中较为常见且影响较大的就是 cluster_block_exception 错误。 本文将深入解析这种错…

Springboot项目

《《《《《《《《《《《------ 项目建立 ------》》》》》》》》》》》》 1.新建项目&#xff0c;选择Spring Initializer&#xff08;新版本选择Spring boot&#xff09; 我的项目是JDK1.8的&#xff0c;所以在项目SDK就选择了1.8版本的&#xff0c;选择启动服务URL地…

2024江苏省赛E. Divide

补题链接 题目大意: 每次操作会把区间内最大值除以2&#xff0c;q次询问&#xff0c;问[l,r]操作k次后的结果是什么 分析: 一道主席树的题目,可以先最整个区间一直进行除以2的操作&#xff0c;问区间[l,r]操作后结果&#xff0c;其实就可以转化为求区间第k1大的结果,反转一下…