建造者模式

133 阅读5分钟

建造者模式简介

一句话介绍:建造者模式是一种创建型设计模式,可以用它将一个复杂产品对象的构造过程分解成一系列接口形式的步骤,这些步骤都可以用不同的方式实现,使得同样的构建过程可以实现不同的产品表示(Representation)需求。

2. 建造者模式的组成

建造者模式的核心思想是将一个复杂对象的构建过程分解为多个简单的步骤,然后由不同的具体建造者实现这些步骤,最终由指挥者调用具体建造者的方法来构建产品对象。这样做的好处是可以根据需求组合不同的具体建造者和指挥者,实现不同的构建过程和产品表示,从而提高系统的灵活性和可维护性。

建造者模式包含五个主要角色:

  • 产品(Product):被构建的复杂对象, 包含多个组成部分或者包含多个创建步骤;
  • 抽象建造者(Abstract Builder):定义构建产品各个部分的抽象接口和一个返回复杂产品的方法getResult
  • 具体建造者(Concrete Builder):实现抽象建造者接口,构建产品的各个组成部分,并提供一个方法返回最终的产品;
  • 指挥者(Director):调用具体建造者的方法,按照一定的顺序或逻辑来构建产品;
  • 客户端/调用方(Client)通过指挥者来构建产品,而并不和具体建造者进行直接的交互,但是它必须将某个具体建造者对象与指挥者对象建立关联。

3. 建造者模式的使用场景以及优缺点

使用场景:

  • 当一个对象的构建过程比较复杂,需要通过多个步骤来构建时,可以使用建造者模式;
  • 当需要构建的产品有多种表示时,可以使用建造者模式来实现不同的表示;
  • 当需要避免构建过程中的耦合性时,可以使用建造者模式。

优点:

  • 将构建过程和表示分离,使得同样的构建过程可以创建不同的表示;
  • 可以更加灵活地组合不同的具体建造者和指挥者,实现不同的构建过程和产品表示;
  • 可以避免构建过程中的耦合性,使得系统更加易于维护和扩展。

缺点:

  • 建造者模式中需要定义多个具体建造者和指挥者,增加了系统的复杂性。

4. 使用Python实现建造者模式

下面是使用Python实现建造者模式的简单示例:

from abc import ABC, abstractmethod

# 产品类
class Product:
    def __init__(self):
        self.parts = []

    def add_part(self, part):
        self.parts.append(part)

    def show(self):
        for part in self.parts:
            print(part)

# 抽象建造者类
class Builder(ABC):
    @abstractmethod
    def build_part1(self):
        raise NotImplemented

    @abstractmethod
    def build_part2(self):
        raise NotImplemented

    @abstractmethod
    def get_result(self) -> Product:
        raise NotImplemented

# 具体建造者类
class ConcreteBuilder1(Builder):
    def __init__(self):
        self.product = Product()

    def build_part1(self):
        self.product.add_part("Part1 for ConcreteBuilder1")

    def build_part2(self):
        self.product.add_part("Part2 for ConcreteBuilder1")

    def get_result(self) -> Product:
        return self.product

class ConcreteBuilder2(Builder):
    def __init__(self):
        self.product = Product()

    def build_part1(self):
        self.product.add_part("Part1 for ConcreteBuilder2")

    def build_part2(self):
        self.product.add_part("Part2 for ConcreteBuilder2")

    def get_result(self) -> Product:
        return self.product

# 指挥者类
class Director:
    def __init__(self, builder):
        self.builder = builder

    def construct(self):
        self.builder.build_part1()
        self.builder.build_part2()

# 客户端代码
if __name__ == "__main__":
    # 使用具体建造者1构建产品
    builder1 = ConcreteBuilder1()
    director1 = Director(builder1)
    director1.construct()
    product1 = builder1.get_result()
    product1.show()

    # 使用具体建造者2构建产品
    builder2 = ConcreteBuilder2()
    director2 = Director(builder2)
    director2.construct()
    product2 = builder2.get_result()
    product2.show()

在这个示例中,我们定义了产品类 Product,抽象建造者类 Builder,具体建造者类 ConcreteBuilder1ConcreteBuilder2,以及指挥者类 Director。客户端代码可以通过具体建造者和指挥者来构建产品对象,而不需要直接实例化具体的产品类,从而实现了建造者模式。

5. 参考文章

6. 简单练习题:【设计模式专题之建造者模式】4. 自行车加工

""" 
【设计模式专题之建造者模式】4. 自行车加工
时间限制:1.000S  空间限制:256MB
题目描述
小明家新开了一家自行车工厂,用于使用自行车配件(车架 frame 和车轮 tires )进行组装定制不同的自行车,包括山地车和公路车。

山地车使用的是Aluminum Frame(铝制车架)和 Knobby Tires(可抓地轮胎),公路车使用的是 Carbon Frame (碳车架)和 Slim Tries。

现在它收到了一笔订单,要求定制一批自行车,请你使用【建造者模式】告诉小明这笔订单需要使用那些自行车配置吧。


输入描述
输入的第一行是一个整数 N(1 ≤ N ≤ 100),表示订单的数量。 

接下来的 N 行,每行输入一个字符串,字符串表示客户的自行车需求。

字符串可以包含关键词 "mountain" 或 "road",表示客户需要山地自行车或公路自行车。

输出描述
对于每笔订单,输出该订单定制的自行车配置。
输入示例
3
mountain
road
mountain
输出示例
Aluminum Frame Knobby Tires
Carbon Frame Slim Tires
Aluminum Frame Knobby Tires
提示信息
在本例中:产品为自行车,可以有两个建造者:山地车建造者和公路车建造者。
"""

from abc import ABC, abstractmethod


class Bike:
    def __init__(self):
        self._frame = None
        self._tires = None
        
    @property 
    def frame(self):
        return self._frame
        
    @frame.setter
    def frame(self, f: str):
        self._frame = f 
        
    @property 
    def tires(self):
        return self._tires
        
    @tires.setter
    def tires(self, t):
        self._tires = t 
        
    def show(self):
        print("{} {}".format(self.frame, self.tires))


class Builder(ABC):
    @abstractmethod
    def setFrame(self):
        raise NotImplemented
        
    @abstractmethod
    def setTires(self):
        raise NotImplemented
        
    def getResult(self) -> Bike:
        raise NotImplemented
        
        
class MountainBikeBuilder(Builder):
    def __init__(self):
        self._bike = Bike()
        
    def setFrame(self):
        self._bike.frame = "Aluminum Frame"
        
    def setTires(self):
        self._bike.tires = "Knobby Tires"
        
    def getResult(self) -> Bike:
        return self._bike
        
        
class RoadBikeBuilder(Builder):
    def __init__(self):
        self._bike = Bike()
        
    def setFrame(self):
        self._bike.frame = "Carbon Frame"
        
    def setTires(self):
        self._bike.tires = "Slim Tires"
        
    def getResult(self) -> Bike:
        return self._bike
        
        
class Director:
    def __init__(self, builder: Builder):
        self._builder = builder
        
    def build(self):
        self._builder.setFrame()
        self._builder.setTires()
        
        
def client():
    bikes = []
    n = int(input())
    for _ in range(n):
        bikeType = input()
        if bikeType == "mountain":
            builder = MountainBikeBuilder()
        if bikeType == "road":
            builder = RoadBikeBuilder()
        director = Director(builder)
        director.build()
        bike = builder.getResult()
        bikes.append(bike)
    for bike in bikes:
        bike.show()
        
        
if __name__ == "__main__":
    client()