意图:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
结构:
示例:
Builder(TextConverter):为创建产品对象的各个部件提供抽象接口。
class TextConverter(ABC):
@abstractmethod
def convert_character(self, char):
"""转换普通文本"""
@abstractmethod
def convert_font_change(self, font):
"""转换RTF控制字"""
@abstractmethod
def convert_paragraph(self):
"""转换RTF标记"""
ConcreteBuilder(ASCIIConverter、TeXConverter、TextWidgetConverter):实现Builder接口来构造或装配产品的各个部件,提供一个检索产品的接口(返回产品对象)。
class ASCIIConverter(TextConverter):
def __init__(self):
self.__ascii_text = ASCIIText()
def convert_character(self, char):
converted_char = ascii(char)
print('convert character(%s) with ascii' % converted_char)
self.__ascii_text.char.append(converted_char)
def convert_font_change(self, font):
raise AttributeError('ascii converter cant convert font change')
def convert_paragraph(self):
raise AttributeError('ascii converter cant convert paragraph')
def get_ascii_text(self):
"""返回ascii编码文本"""
return self.__ascii_text
class TeXConverter(TextConverter):
def __init__(self):
self.__tex_text = TeXText()
def convert_character(self, char):
converted_char = char.upper()
print('convert character(%s) with TeX' % converted_char)
self.__tex_text.char.append(converted_char)
def convert_font_change(self, font):
converted_font = font.upper()
print('convert font_change(%s) with TeX' % converted_font)
self.__tex_text.font.append(converted_font)
def convert_paragraph(self):
print('convert paragraph with TeX')
self.__tex_text.para.append('para')
def get_tex_text(self):
"""返回tex风格文本"""
return self.__tex_text
class TextWidgetConverter(TextConverter):
def __init__(self):
self.__text_widget = TextWidget()
def convert_character(self, char):
print('convert character(%s) with TextWidget' % char)
self.__text_widget.char.append(char)
def convert_font_change(self, font):
print('convert font_change(%s) with TextWidget' % font)
self.__text_widget.font.append(font)
def convert_paragraph(self):
print('convert paragraph with TextWidget')
self.__text_widget.para.append('para')
def get_text_widget(self):
"""返回文本组件"""
return self.__text_widget
Director(RTFReader):构造一个使用Builder接口的对象,提供了construct建造方法,该方法中应该调用Builder中的创建各部件的接口(此时实际装配了一个完整的产品)。
class RTFReader:
def __init__(self, builder: TextConverter):
self.builder = builder
def parse_RTF(self, rtf_list):
"""construct()建造方法"""
for rtf in rtf_list:
if rtf.sign == 'CHAR':
self.builder.convert_character(rtf.char)
elif rtf.sign == 'FONT':
self.builder.convert_font_change(rtf.font)
elif rtf.sign == 'PARA':
self.builder.convert_paragraph()
Product(ASCIIText、TeXText、TextWidget):表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。
class ASCIIText:
def __init__(self):
self.char = []
def show(self):
print('ascii text: %s' % ''.join(self.char))
class TeXText:
def __init__(self):
self.char = []
self.font = []
self.para = []
def show(self):
print('TeX char: %s' % ''.join(self.char))
print('TeX font: %s' % ''.join(self.font))
print('TeX para: %s' % ''.join(self.para))
class TextWidget:
def __init__(self, window='PC_WINDOW'):
self.window = window
self.char = []
self.font = []
self.para = []
def show(self):
print('show text: %s in %s' % (''.join(self.char), self.window))
print('show text: %s in %s' % (''.join(self.font), self.window))
print('show text: %s in %s' % (''.join(self.para), self.window))
Client:利用所需的Builder创建Director对象,利用建造方法construct(),构建产品的各个部件,最后从Builder中获取完整的产品。
交互图:
分析:
- Builder提供给Directror构造产品的抽象接口,该接口隐藏了产品的表示和内部结构,以及产品是如何装配的。当改变产品的内部结构时,只需要重新定义一个ConcreteBuilder,并改变其内部的部件装备的结构(如将TeX风格的普通文本改为str.lower()时,只要重新定义ConcreteBuilder,并修改部件的装配方法)。
- 对产品的构造过程进行更精细的控制。产品是在导向者Director的控制下,一步一步的构造完成的,且仅当各个部件构造结束成为完整的产品时才从Builder中取回该产品。
- Builder着重于一步一步构造一个复杂对象,且在最后一步构造完成时返回。而Abstract Factory着重于多个系列同个产品族的产品对象,且该对象是立刻返回的。