创建型模式:对象的诞生艺术
在面向对象编程的世界里,创建对象就像一场精心策划的仪式。如果每次都用 new 关键字直接实例化,就像在婚礼现场临时找证婚人------虽然能完成,但缺乏优雅和复用性。创建型模式(Creational Patterns)正是为了解决这个问题而生:它们将对象的"创建过程"与"使用过程"解耦,让代码更灵活、更可维护。今天,我们就从基础到高级,层层剥开这些模式的奥秘。---### 一、为什么要关注创建型模式?想象一下,你正在开发一个游戏,需要生成不同类型的敌人。如果直接在代码里写 if (type == "zombie") return new Zombie();,每次新增敌人类型都要修改这段逻辑,这违反了"开闭原则"(对扩展开放,对修改关闭)。创建型模式的核心思想是:让创建过程独立于具体类型 ,从而支持变化。创建型模式主要包含五种经典模式:- 单例模式 :保证一个类仅有一个实例,并提供一个全局访问点。- 工厂方法模式 :定义一个创建对象的接口,让子类决定实例化哪个类。- 抽象工厂模式 :创建相关或依赖对象的家族,而不指定具体类。- 建造者模式 :将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。- 原型模式 :通过复制现有实例来创建新对象,而不是通过 new。下面我们逐一深入,并附上可运行的代码示例。---### 二、基础篇:单例模式(Singleton)场景 :你需要一个全局配置管理器,整个程序只允许一个实例,避免资源浪费或状态不一致。核心实现 :将构造函数设为私有(或受保护),静态方法返回唯一实例。注意线程安全。pythonclass ConfigManager: _instance = None # 类变量,存储唯一实例 def __new__(cls): # 重写 __new__ 控制实例创建 if cls._instance is None: # 如果还没有实例,则创建并保存 cls._instance = super().__new__(cls) # 初始化配置(此处仅作演示) cls._instance.settings = {"theme": "dark", "volume": 0.8} return cls._instance def get_setting(self, key): return self.settings.get(key)# 测试代码config1 = ConfigManager()config2 = ConfigManager()print(config1 is config2) # True,说明是同一个实例print(config1.get_setting("theme")) # 输出: dark优点 :全局访问方便,节省内存。 缺点 :全局状态可能被滥用,且不利于单元测试(难以隔离)。 进阶 :在 Python 中,可以使用 threading.Lock 保证多线程下的安全,但这里简化了。---### 三、工厂方法模式(Factory Method)场景 :你有一个日志系统,需要支持不同格式(如 JSON、XML)。工厂方法模式让子类决定创建哪种日志对象。核心思想 :定义一个抽象的 create_logger 方法,让子类重写它。pythonfrom abc import ABC, abstractmethod# 抽象产品:日志接口class Logger(ABC): @abstractmethod def log(self, message): ...# 具体产品:JSON 日志class JsonLogger(Logger): def log(self, message): print(f'{``{"msg": "{message}"}}')# 具体产品:XML 日志class XmlLogger(Logger): def log(self, message): print(f'<message>{message}</message>')# 抽象工厂(创建者)class LoggerFactory(ABC): @abstractmethod def create_logger(self) -> Logger: ...# 具体工厂:JSON 工厂class JsonLoggerFactory(LoggerFactory): def create_logger(self): return JsonLogger()# 具体工厂:XML 工厂class XmlLoggerFactory(LoggerFactory): def create_logger(self): return XmlLogger()# 使用示例factory = JsonLoggerFactory()logger = factory.create_logger() # 运行时决定创建 JsonLoggerlogger.log("Hello") # 输出: {"msg": "Hello"}factory = XmlLoggerFactory()logger = factory.create_logger()logger.log("Hi") # 输出: <message>Hi</message>优点 :新增日志类型时,只需添加新的产品和工厂类,无需修改现有代码。 缺点 :每新增一种产品,就要增加两个类(产品和工厂),类数量膨胀。---### 四、进阶篇:抽象工厂模式(Abstract Factory)场景 :你正在开发跨平台 UI 组件,需要为 Windows 和 macOS 分别生成按钮和输入框。这些组件是"相关对象家族"------按钮和输入框必须匹配同一风格。核心 :抽象工厂声明创建多个产品的方法,具体工厂实现这些方法,保证产品族的一致性。pythonfrom abc import ABC, abstractmethod# 抽象产品:按钮class Button(ABC): @abstractmethod def paint(self): ...# 抽象产品:输入框class Input(ABC): @abstractmethod def render(self): ...# 具体产品:Windows 风格class WinButton(Button): def paint(self): print("Windows 风格按钮")class WinInput(Input): def render(self): print("Windows 风格输入框")# 具体产品:macOS 风格class MacButton(Button): def paint(self): print("macOS 风格按钮")class MacInput(Input): def render(self): print("macOS 风格输入框")# 抽象工厂class UIFactory(ABC): @abstractmethod def create_button(self) -> Button: ... @abstractmethod def create_input(self) -> Input: ...# 具体工厂class WinFactory(UIFactory): def create_button(self): return WinButton() def create_input(self): return WinInput()class MacFactory(UIFactory): def create_button(self): return MacButton() def create_input(self): return MacInput()# 使用:根据平台选择工厂def create_ui(factory: UIFactory): btn = factory.create_button() inp = factory.create_input() btn.paint() inp.render()# 模拟运行时平台platform = "windows" # 假设从配置读取factory = WinFactory() if platform == "windows" else MacFactory()create_ui(factory)# 输出: Windows 风格按钮 / Windows 风格输入框优点 :保证产品族的一致性,符合"依赖倒置原则"。 缺点 :增加新的产品族(如 Linux)较为繁琐,需改动所有抽象工厂接口。---### 五、高级篇:建造者模式(Builder)场景 :你想构建一个复杂的 Computer 对象,它包含 CPU、内存、硬盘等部件,且组装顺序可能变化。建造者模式将构建过程分解为多个步骤,并允许分步执行。核心 :Director 控制构建顺序,Builder 负责具体部件的组装。python# 产品:电脑class Computer: def __init__(self): self.cpu = None self.ram = None self.storage = None def __str__(self): return f"CPU: {self.cpu}, RAM: {self.ram}, Storage: {self.storage}"# 建造者接口class ComputerBuilder(ABC): @abstractmethod def build_cpu(self): ... @abstractmethod def build_ram(self): ... @abstractmethod def build_storage(self): ... @abstractmethod def get_result(self) -> Computer: ...# 具体建造者:游戏电脑class GamingComputerBuilder(ComputerBuilder): def __init__(self): self.computer = Computer() def build_cpu(self): self.computer.cpu = "i9-13900K" def build_ram(self): self.computer.ram = "64GB DDR5" def build_storage(self): self.computer.storage = "2TB NVMe SSD" def get_result(self): return self.computer# 具体建造者:办公电脑class OfficeComputerBuilder(ComputerBuilder): def __init__(self): self.computer = Computer() def build_cpu(self): self.computer.cpu = "i5-13400" def build_ram(self): self.computer.ram = "16GB DDR4" def build_storage(self): self.computer.storage = "512GB SSD" def get_result(self): return self.computer# 导演:控制构建顺序class Director: def __init__(self, builder: ComputerBuilder): self.builder = builder def construct(self): # 按特定顺序组装 self.builder.build_cpu() self.builder.build_ram() self.builder.build_storage() return self.builder.get_result()# 使用builder = GamingComputerBuilder()director = Director(builder)pc = director.construct()print(pc) # 输出: CPU: i9-13900K, RAM: 64GB DDR5, Storage: 2TB NVMe SSD优点 :可以灵活调整构建步骤,且产品内部表示可以变化。 缺点 :代码量增多,适合对象复杂且构建步骤固定的场景。---### 六、原型模式(Prototype)场景 :你有一个包含大量默认配置的对象,每次创建新对象时,只需复制现有对象并修改少数属性。原型模式通过克隆来创建新对象。核心 :实现 clone 方法(在 Python 中可以用 copy 模块),注意深拷贝/浅拷贝。pythonimport copyclass Document: def __init__(self, title, content, tags): self.title = title self.content = content self.tags = tags # 列表类型,需要深拷贝 def clone(self, **kwargs): """克隆自身,并允许覆盖属性""" cloned = copy.deepcopy(self) # 深拷贝避免共享引用 for key, value in kwargs.items(): setattr(cloned, key, value) return cloned def __str__(self): return f"Document(title={self.title}, tags={self.tags})"# 使用template = Document("默认文档", "内容", ["默认"])doc1 = template.clone(title="项目计划", tags=["项目", "计划"])doc2 = template.clone(title="会议记录", tags=["会议"])print(doc1) # 输出: Document(title=项目计划, tags=['项目', '计划'])print(doc2) # 输出: Document(title=会议记录, tags=['会议'])print(template) # 原模板未被修改优点 :减少初始化开销(尤其当对象创建代价高时),运行时动态创建新类型。 缺点 :深拷贝可能复杂,且每个类都需要实现克隆逻辑。---### 七、模式对比与选择指南| 模式 | 核心用途 | 适用场景 ||------|----------|----------|| 单例 | 全局唯一实例 | 配置管理、连接池 || 工厂方法 | 一个产品等级结构 | 日志、文件解析 || 抽象工厂 | 多个产品等级结构 | UI 组件、跨平台库 || 建造者 | 复杂对象分步构建 | 配置对象、报告生成 || 原型 | 通过复制创建 | 对象初始化昂贵、需要动态变体 |选择建议 :如果对象只有一种,用单例;如果有一组相关对象,用抽象工厂;如果构建过程很复杂,用建造者;如果创建成本高,用原型。---### 八、总结创建型模式是对象诞生艺术的精华所在。它们不仅仅是代码技巧,更是对"变化"的哲学思考------如何让系统在需求变化时保持稳定。从单例的"唯一性"到抽象工厂的"家族一致性",从建造者的"分步构建"到原型的"复制即创造",每种模式都在解决特定场景下的问题。核心要点 :- 解耦 :创建逻辑与业务逻辑分离。- 扩展 :通过多态和接口实现开放-封闭原则。- 灵活:在运行时决定创建什么、如何创建。在实际项目中,不要盲目套用模式。先评估代码的复杂度和变化频率,再选择最合适的工具。记住,模式是辅助思考的工具,而非目的本身。当你开始用"创建"的眼光看待对象时,你的代码就已经迈入了艺术的行列。