前言
GOF设计模式分三大类:
- 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
- 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
- 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。
一、建造者模式
建造者模式(Builder Pattern)
-
定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
-
解决问题:如何一步步创建一个包含多个组成部分的复杂对象?
-
使用场景:
- 建造者模式向客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品。
- 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
-
组成:
-
复杂产品(Product):最终要构建的复杂对象。 复杂对象是指那些包含多个成员变量的对象,这些成员变量也称为部件或零件。
-
抽象建造者(Builder):为一个抽象接口,定义了构建产品的各个部件的操作。
-
具体建造者(Concrete Builder):实现抽象建造者的接口,定义并明确各个部件的具体实现。
-
(可省略)指挥者(Director):负责安排已有模块的构建顺序,它主要用来控制产品的创建过程。
-
-
优点:
- 客户端无须知道复杂对象的内部组成部分与装配方式,只需要知道所需的建造者类型即可。
- 建造者模式关注如何一步一步地创建一个复杂对象,不同的具体建造者定义了不同的创建过程,且具体建造者相互独立,增加新的建造者非常方便,无须修改已有代码,系统具有较好的扩展性。
- 可以更加精细地控制产品的创建过程。
-
缺点:
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似。否则不适用。
二、建造者模式示例
使用建造者模式来实现游戏角色的创建
- ActorController充当指挥者,ActorBuilder充当抽象建造者,HeroBuilder、AngelBuilder和DevilBuilder充当具体建造者,Actor充当复杂产品。
"""复杂产品"""
class Actor:
def __init__(self, type=None, sex=None, face=None, costume=None, hairstyle=None):
self.type = type
self.sex = sex
self.face = face
self.costume = costume
self.hairstyle = hairstyle
"""抽象建造者"""
class ActorBuilder:
def __init__(self):
self.actor = Actor()
def build_type(self):
raise NotImplementedError
def build_sex(self):
raise NotImplementedError
def build_face(self):
raise NotImplementedError
def build_costume(self):
raise NotImplementedError
def build_hairstyle(self):
raise NotImplementedError
def create_actor(self) -> Actor:
return self.actor
"""具体建造者"""
class HeroBuilder(ActorBuilder):
def build_type(self):
self.actor.type = "英雄"
def build_sex(self):
self.actor.sex = "男"
def build_face(self):
self.actor.face = "英俊"
def build_costume(self):
self.actor.costume = "盔甲"
def build_hairstyle(self):
self.actor.hairstyle = "飘逸"
class AngelBuilder(ActorBuilder):
def build_type(self):
self.actor.type = "天使"
def build_sex(self):
self.actor.sex = "女"
def build_face(self):
self.actor.face = "漂亮"
def build_costume(self):
self.actor.costume = "白裙"
def build_hairstyle(self):
self.actor.hairstyle = "披肩长发"
"""指挥者"""
class ActorController:
def construct(self, ab: ActorBuilder):
ab.build_type()
ab.build_sex()
ab.build_face()
ab.build_costume()
ab.build_hairstyle()
return ab.create_actor()
引入配置文件config.json
{
"class_name": "AngelBuilder"
}
读取配置文件的工具类JsonUtil
# 模块 utils.py
from pathlib import Path
import json
class JsonUtil:
@staticmethod
def get_class_name():
"""读取配置文件,返回配置文件中的配置"""
path = Path("config.json")
contents = path.read_text(encoding="utf-8")
conf = json.loads(contents)
return conf.get("class_name", None)
客户端代码
import actors
from actors import Actor, ActorBuilder, ActorController
from utils import JsonUtil
def display(actor: Actor):
print(f"类型:{actor.type}")
print(f"性别:{actor.sex}")
print(f"面容:{actor.face}")
print(f"服装:{actor.costume}")
print(f"发型:{actor.hairstyle}")
class_name = JsonUtil.get_value("class_name")
klass = getattr(actors, class_name, None)
if klass:
ab: ActorBuilder = klass() # 反射生成具体建造者对象
ac = ActorController()
actor = ac.construct(ab) # 通过指挥者创建完整的建造者对象
display(actor)
输出结果
类型:天使
性别:女
面容:漂亮
服装:白裙
发型:披肩长发
三、省略指挥者(建议)
当construct()方法较为简单时,建议省略指挥者。简化了系统结构,但加重了抽象建造者类的职责。
- 将construct()方法直接放在抽象建造者中,具体建造者可以沿用或改写construct()方法。
"""复杂产品(不变)"""
"""抽象建造者(用construct()方法替换原来的create_actor()方法)"""
class ActorBuilder:
def __init__(self):
self.actor = Actor()
def build_type(self):
raise NotImplementedError
def build_sex(self):
raise NotImplementedError
def build_face(self):
raise NotImplementedError
def build_costume(self):
raise NotImplementedError
def build_hairstyle(self):
raise NotImplementedError
def construct(self) -> Actor:
self.build_type()
self.build_sex()
self.build_face()
self.build_costume()
self.build_hairstyle()
return self.actor
"""具体建造者(不变)"""
"""指挥者(可以删除)"""
客户端代码
import actors
from actors import Actor, ActorBuilder
from utils import JsonUtil
def display(actor: Actor):
print(f"类型:{actor.type}")
print(f"性别:{actor.sex}")
print(f"面容:{actor.face}")
print(f"服装:{actor.costume}")
print(f"发型:{actor.hairstyle}")
class_name = JsonUtil.get_value("class_name")
klass = getattr(actors, class_name, None)
if klass:
ab: ActorBuilder = klass() # 反射生成具体建造者对象
actor = ab.construct()
display(actor)
四、钩子方法的引入
钩子方法的返回类型通常为boolean类型,方法名一般为isxx()
。
- 钩子方法定义在抽象建造者类中,提供默认的实现,对应的具体建造者可以覆盖钩子方法。例如:
"""抽象建造者"""
class ActorBuilder:
#...
def is_bareheaded(self):
return False
#...
- construct()方法的作用是:实现更加精细地控制产品的创建过程。
- 通过在construct()方法中,配合使用钩子方法,实现更灵活的建造过程。
"""抽象建造者"""
class ActorBuilder:
#...
def construct(self) -> Actor:
self.build_type()
self.build_sex()
self.build_face()
self.build_costume()
if not self.is_bareheaded():
self.build_hairstyle()
return self.actor
#...
您正在阅读的是《设计模式Python版》专栏!关注不迷路~