您的位置:首页 > 编程语言 > Python开发

python创建型设计模式——建造者模式

2017-01-02 20:27 435 查看

建造者模式

与工厂模式相似,用于创建需要由多个对象组成的复杂对象。区别在于他不仅提供了创建复杂对象所需要的方法,而且保存了复杂对象里的各个部分的细节。适用于需要把复杂对象各个部分的细节与其创建流程相分离的场合。

表单生成程序的例子,分别生成HTML和ThinkerGUI表单



最顶层调用

创建两个表单,并分别写入对应文件中,都会调用create_login_form()并传入建造者对象

def main():
if len(sys.argv) > 1 and sys.argv[1] == "-P": # For regression testing
print(create_login_form(HtmlFormBuilder()))
print(create_login_form(TkFormBuilder()))
return

htmlFilename = os.path.join(tempfile.gettempdir(), "login.html")
htmlForm = create_login_form(HtmlFormBuilder())
with open(htmlFilename, "w", encoding="utf-8") as file:
file.write(htmlForm)
print("wrote", htmlFilename)

tkFilename = os.path.join(tempfile.gettempdir(), "login.py")
tkForm = create_login_form(TkFormBuilder())
with open(tkFilename, "w", encoding="utf-8") as file:
file.write(tkForm)
print("wrote", tkFilename)


create_login_form()函数

调用builder的设置方法,然后由builder拼接对象,返回复杂的对象。与工厂模式的却别在于,工厂模式这里是直接由工厂创建相关简单对象以及复杂对象,复杂对象调用自己的方法进行拼接,然后返回自己

def create_login_form(builder):
builder.add_title("Login")
builder.add_label("Username", 0, 0, target="username")
builder.add_entry("username", 0, 1)
builder.add_label("Password", 1, 0, target="password")
builder.add_entry("password", 1, 1, kind="password")
builder.add_button("Login", 2, 0)
builder.add_button("Cancel", 2, 1)
return builder.form()


建造者类

HtmlFormBuilder类

表单中的控件保存在items字典中,字典的键是row与column构成的二元组,值为控件html代码

class HtmlFormBuilder(AbstractFormBuilder):

def __init__(self):
self.title = "HtmlFormBuilder"
self.items = {}

def add_title(self, title):
super().add_title(escape(title))

def add_label(self, text, row, column, **kwargs):
self.items[(row, column)] = ('<td><label for="{}">{}:</label></td>'
.format(kwargs["target"], escape(text)))

def add_entry(self, variable, row, column, **kwargs):
html = """<td><input name="{}" type="{}" /></td>""".format(
variable, kwargs.get("kind", "text"))
self.items[(row, column)] = html

def add_button(self, text, row, column, **kwargs):
html = """<td><input type="submit" value="{}" /></td>""".format(
escape(text))
self.items[(row, column)] = html

def form(self):
html = ["<!doctype html>\n<html><head><title>{}</title></head>"
"<body>".format(self.title), '<form><table border="0">']
thisRow = None
for key, value in sorted(self.items.items()):
row, column = key
if thisRow is None:
html.append("  <tr>")
elif thisRow != row:
html.append("  </tr>\n  <tr>")
thisRow = row
html.append("    " + value)
html.append("  </tr>\n</table></form></body></html>")
return "\n".join(html)


TkFormBuilder类

由statement字典来存放组件创建和设置的语句,有extends()函数来扩充该字典。_canonicalize()用于格式化处理字符串,设置在数字开头的字符串前增加 “_”,并且可以根据需要,设置首字母大小写

class TkFormBuilder(AbstractFormBuilder):

TEMPLATE = """#!/usr/bin/env python3
import tkinter as tk
import tkinter.ttk as ttk

class {name}Form(tk.Toplevel):

def __init__(self, master):
super().__init__(master)
self.withdraw()     # hide until ready to show
self.title("{title}")
{statements}
self.bind("<Escape>", lambda *args: self.destroy())
self.deiconify()    # show when widgets are created and laid out
if self.winfo_viewable():
self.transient(master)
self.wait_visibility()
self.grab_set()
self.wait_window(self)

if __name__ == "__main__":
application = tk.Tk()
window = {name}Form(application)
application.protocol("WM_DELETE_WINDOW", application.quit)
application.mainloop()
"""

def __init__(self):
self.title = "TkFormBuilder"
self.statements = []

def add_title(self, title):
super().add_title(title)

def add_label(self, text, row, column, **kwargs):
name = self._canonicalize(text)
create = """self.{}Label = ttk.Label(self, text="{}:")""".format(
name, text)
layout = """self.{}Label.grid(row={}, column={}, sticky=tk.W, \
padx="0.75m", pady="0.75m")""".format(name, row, column)
self.statements.extend((create, layout))

def add_entry(self, variable, row, column, **kwargs):
name = self._canonicalize(variable)
extra = "" if kwargs.get("kind") != "password" else ', show="*"'
create = "self.{}Entry = ttk.Entry(self{})".format(name, extra)
layout = """self.{}Entry.grid(row={}, column={}, sticky=(\
tk.W, tk.E), padx="0.75m", pady="0.75m")""".format(name, row, column)
self.statements.extend((create, layout))

def add_button(self, text, row, column, **kwargs):
name = self._canonicalize(text)
create = ("""self.{}Button = ttk.Button(self, text="{}")"""
.format(name, text))
layout = """self.{}Button.grid(row={}, column={}, padx="0.75m", \
pady="0.75m")""".format(name, row, column)
self.statements.extend((create, layout))

def form(self):
return TkFormBuilder.TEMPLATE.format(title=self.title,
name=self._canonicalize(self.title, False),
statements="\n        ".join(self.statements))

def _canonicalize(self, text, startLower=True):
text = re.sub(r"\W+", "", text)
if text[0].isdigit():
return "_" + text
return text if not startLower else text[0].lower() + text[1:]


补充知识点

python tempfile 模块

http://blog.csdn.net/liangzhao_jay/article/details/17719953

python继承的实现:

基类设置mateclass参数为abc模块中的ABCMeta,并用 @abc.abstractmethod装饰器装饰抽象方法。如果这么设置,则该类将无法初始化,但是会增加运行期开销,一般采用更为宽松的做法,不用mateclass,而是直接在文档中说明,该类是抽象基类。

class AbstractFormBuilder(metaclass=abc.ABCMeta):

@abc.abstractmethod
def add_title(self, title):
self.title = title

@abc.abstractmethod
def form(self):
pass

@abc.abstractmethod
def add_label(self, text, row, column, **kwargs):
pass

@abc.abstractmethod
def add_entry(self, variable, row, column, **kwargs):
pass

@abc.abstractmethod
def add_button(self, text, row, column, **kwargs):
pass


序列与映射的解包操作:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息