当前位置: 首页 > news >正文

Python 中的 Builder 模式实践 —— 以 UserProfileBuilder 为例

一. 背景

在开发中,我们经常需要创建复杂对象(DTO,配置,请求体等)

这些对象属性很多,但是并不是每次都需要全部填写:

  • 有些属性可以用默认值
  • 有些属性可以随机生成
  • 有些属性依赖其他对象

如果直接用构造函数,代码会像下面这样,可读性比较差

profile = UserProfile(username="alice",email="alice@example.com",role="admin",tags=["tester"],colors=["red"],preferences=[]
)

Bulider模式可以帮我们解决这个问题

二. 什么是 Builder 模式?

1、Builder模式(构造者模式)是一种创建型设计模式

  • 把“任何一步步创建对象”的逻辑抽离到一个Builder类里;
  • 让调用方用链式方法逐步设置属性;
  • 支持默认值、随机值、依赖值等灵活逻辑。

2、优点:

  • 可读性强
  • 灵活性高
  • 方便扩展和默认值处理

三、代码示例

1、BuliderBase提供通用的create方法:

from typing import Any, Type, TypeVarT = TypeVar("T", bound="BuilderBase")class BuilderBase:@classmethoddef create(cls: Type[T], **kwargs) -> Any:"""通用创建方法:根据 kwargs 自动调用 with_xxx 方法或直接赋值。"""builder = cls()for key, value in kwargs.items():method_name = f"with_{key}"if hasattr(builder, method_name):getattr(builder, method_name)(value)else:setattr(builder, key, value)return builder.build_object()

2、UserProFileBulider:具体实现

import random
from typing import List, Optionalclass UserProfileBuilder(BuilderBase):def __init__(self):self.username: Optional[str] = Noneself.email: Optional[str] = Noneself.role: Optional[str] = Noneself.tags: List[str] = []self.colors: List[str] = []self.preferences: List[str] = []def enable_randomized_attributes(self, enabled: bool):"""开启随机属性生成"""if enabled:self.with_random_attributes()return selfdef with_random_attributes(self, number: Optional[int] = None):"""随机生成标签和颜色"""color_pool = ["red", "blue", "green", "yellow"]tag_pool = ["admin", "tester", "developer", "guest"]max_count = min(len(color_pool), len(tag_pool))if number is None:number = random.randint(1, max_count)count = min(number, max_count)self.colors = random.sample(color_pool, k=count)self.tags = random.sample(tag_pool, k=count)return selfdef build_object(self):"""构建 UserProfile 对象"""if self.username is None:self.username = "default_user"return UserProfile(username=self.username,email=self.email,role=self.role,tags=list(self.tags),colors=list(self.colors),preferences=list(self.preferences),)class UserProfile:"""最终要构建的对象"""def __init__(self, username, email, role, tags, colors, preferences):self.username = usernameself.email = emailself.role = roleself.tags = tagsself.colors = colorsself.preferences = preferencesdef __repr__(self):return f"<UserProfile {self.username}, {self.role}>"

3、使用示例

# 方式一:一步完成
profile = UserProfileBuilder.create(username="alice",email="alice@example.com",role="admin",enable_randomized_attributes=True
)# 方式二:链式调用
builder = UserProfileBuilder()
profile2 = (builder.with_random_attributes(2).enable_randomized_attributes(True).build_object()
)print(profile)
print(profile2)

4、优点

  • 可读性强:链式 API 一看就懂。

  • 灵活性高:可自由组合不同的 with_xxx 方法。

  • 默认值处理:例如用户名为空时自动填充 default_user

  • 可扩展:新增属性只需加对应的 with_xxx 方法。

5、缺点

  • 对于简单对象,Builder 显得“多余”;

  • 初学者可能不习惯 with_xxx 的用法;

  • 增加了一层抽象。

6、适用场景

  • 测试数据构造(自动化测试用例、随机测试数据)

  • 复杂配置对象(数据库配置、UI 配置、HTTP 请求体)

  • 需要灵活扩展的 DTO

7、传参说明

  • 普通写法
    class UserProfile:def __init__(self, username, email, role):self.username = usernameself.email = emailself.role = roleprofile = UserProfile("alice", "alice@example.com", "admin")
    

    username -> __init__ -> self.username

  • builder模式写法:参数不会直接传给最终的产品类,而是先存放在Builder的属性里(比如:self._username),等到调用build()时,再把这些参数传给UserProfile,由产品类来保存:
    流程:username -> builder._username -> build() -> UserProfile(self.username)
  • 关键区别
    • 普通类:参数直接进构造函数,马上存到属性上。

    • Builder:参数先存到 Builder,等你确认完毕,再一次性传给最终类(更灵活)。

    • 也就是说,self.usernameself.email 这些属性依然存在于 最终的产品类UserProfile)里。
      只是 Builder 先帮你暂存参数,再把它们“打包”交给产品类

http://www.dtcms.com/a/393369.html

相关文章:

  • 探秘陌讯AIGC检测算法优化:详解MPS加速与模型热重载的实现原理
  • 1.3 管道(Pipe)核心知识点总结
  • GLUE:自然语言理解评估的黄金基准
  • 第13章 智能监测-设备数据处理
  • GEO技术科普
  • B004基于三菱FX2NPLC智能自提柜控制系统仿真
  • MTK CPU温度调节一知半解
  • V90伺服驱动器“速度模式“双极性模拟量速度控制
  • 课前练习题-20250919
  • C++类与对象
  • 企业级Docker镜像仓库Harbor
  • ESD防护设计宝典(七):生命线的秩序——关键信号线布线规则
  • 【ROS2】Beginner : CLI tools - 理解 ROS 2 话题
  • RL知识回顾
  • Java多线程编程指南
  • 【论文速读】基于地面激光扫描(TLS)和迭 代最近点(ICP)算法的土坝监测变形分析
  • GAMES101:现代计算机图形学入门(Chapter2 向量与线性代数)迅猛式学线性代数学习笔记
  • 汉语构词智慧:从历史优势到现实考量——兼论“汉语全面改造英语”的可能性
  • 仿tcmalloc高并发内存池
  • 墨者学院-通关攻略(持续更新持续改进)
  • 10厘米钢板矫平机:把“波浪”压成“镜面”的科学
  • ESP32- 项目应用1 智能手表之网络配置 #6
  • TCP/IP 互联网的真相:空间域和时间域的统计学
  • 同步与异步
  • C++中char与string的终极对比指南
  • Java基础 9.20
  • U228721 反转单链表
  • 串行总线、并行总线
  • `HTML`实体插入软连字符: `shy;`
  • 日志驱动切换针对海外vps日志收集的操作标准