Python 的结构型设计模式——适配器模式
2017-01-05 19:14
537 查看
适配器模式
适配器模式是一种接口适配技术,可以通过某个类来使用另一个接口与之不相容的类,运用此模式时,两个类中的接口都无需改动。例如,我们想把某个类从原先的应用场景中拿出来放在另一个环境下运行,而这个类又不能修改,那可以考虑适配器模式。书上的例子:
假设有一个Page类用于渲染页面, 需要知道标题、正文段落以及“渲染器类的实例”。该例子将举出两个渲染器,其中TextRenderer具有相关接口,而HtmlWriter不具有相关接口,需要编写HtmlRenderer适配器类来适配接口。def main(): paragraph1 = MESSAGE.format("plain-text", "TextRenderer") paragraph2 = """This is another short paragraph just so that we can see two paragraphs in action.""" title = "Plain Text" textPage = Page(title, TextRenderer(22)) textPage.add_paragraph(paragraph1) textPage.add_paragraph(paragraph2) textPage.render() print() paragraph1 = MESSAGE.format("HTML", "HtmlRenderer") title = "HTML" file = sys.stdout htmlPage = Page(title, HtmlRenderer(HtmlWriter(file))) htmlPage.add_paragraph(paragraph1) htmlPage.add_paragraph(paragraph2) htmlPage.render() try: page = Page(title, HtmlWriter()) page.render() print("ERROR! rendering with an invalid renderer") except TypeError as err: print(err)
Page类实现
class Page: def __init__(self, title, renderer): if not isinstance(renderer, Renderer) raise TypeError("Expected object of type Renderer, got {}".format(type(renderer).__name__)) def add_paragraph(self, paragraph): self.paragraphs.append(paragraph) def render(self): self.renderer.header(self.title) for paragraph in self.paragraphs: self.renderer.paragraph(paragraph) self.renderer.footer()
说明
要保证__init()__函数收到的确实是一个Renderer实例,可以使用assert isinstance(renderer,Renderer)。此方法有两个缺陷,一方面抛出的是AssertionError,而不是我们希望的TypeError。另一方面如果执行程序的时候使用-o(optimize,优化),则会忽略assert语句,导致AttributeError。于是使用如上代码的验证方式。但是也存在一个问题,就是传入的实例必须继承自Renderer基类。在Java或者c++中确实是这样,但是在python中可以采用另一种做法,既能像抽象基类那样检查接口是否匹配,又能像动态类型那样灵活,换句话说,可以在无需继承特定基类的前提下,创建出符合某套接口的对象。
Renderer基类的实现
isinstance()会调用__subclasshook__(Class,Subclass)来决定函数的首个参数是不是第二个参数的子类,或者是Subclass列表中某个类的子类,这里通过重写__subclasshook__(Class,Subclass),来实现上述说明中的情况
class Renderer(mateclass=abc.ABCMeta): @classmethod def __subclasshook__(Class, Subclass): #判断确实是不是在Renderer上调用的,如果不是就返回NotImplement,并沿着继承体系按照通常的规则继续判定下去,这里会导致子类无法继承 if Class is Renderer: #collections.ChainMap()将所有传进去的映射表当做一张表来看待,__mro__返回Subclass的包括其本身以及其超类的元组。 attributes = collections.ChainMap(*(Superclass.__dict__ for Superclass in Subclass.__mro__)) methods = ("header","paragraph","footer") if all(method in attributes for method in methons): return True return NotImplemented
符合接口要求的TextRenderer
class TextRenderer: def __init__(self, width=80, file=sys.stdout): self.width = width self.file = file self.previous = False def header(self, title): self.file.write("{0:^{2}}\n{1:^{2}}\n".format(title, "=" * len(title), self.width)) def paragraph(self, text): if self.previous: self.file.write("\n") self.file.write(textwrap.fill(text, self.width)) self.file.write("\n") self.previous = True def footer(self): pass
不符合接口要求的HtmlWriter
class Htm 4000 lWriter: def __init__(self, file=sys.stdout): self.file = file def header(self): self.file.write("<!doctype html>\n<html>\n") def title(self, title): self.file.write("<head><title>{}</title></head>\n".format( escape(title))) def start_body(self): self.file.write("<body>\n") def body(self, text): self.file.write("<p>{}</p>\n".format(escape(text))) def end_body(self): self.file.write("</body>\n") def footer(self): self.file.write("</html>\n")
创建HtmlRenderer,适配Renderer接口
class HtmlRenderer: def __init__(self, htmlWriter): self.htmlWriter = htmlWriter def header(self, title): self.htmlWriter.header() self.htmlWriter.title(title) self.htmlWriter.start_body() def paragraph(self, text): self.htmlWriter.body(text) def footer(self): self.htmlWriter.end_body() self.htmlWriter.footer()
相关文章推荐
- Python的结构型设计模式之适配器模式
- 白话设计模式--结构型模式--组合模式,桥接模式和适配器模式
- 结构型设计模式---Adapter模式(适配器模式)
- 设计模式--结构型--适配器模式
- 设计模式(6) 结构型模式和适配器模式(ADAPTER)
- 设计模式7——结构型模式之适配器模式
- 九.结构型设计模式——Adapter Pattern(适配器模式)
- 设计模式(结构型)之适配器模式
- 设计模式(五)适配器模式Adapter(结构型)
- java设计模式(结构型)之适配器模式
- 设计模式笔记 6.Adapter 适配器模式(结构型模式)
- 设计模式笔记(7)---适配器模式(结构型)
- 设计模式笔记(7)---适配器模式(结构型)
- GoF23种设计模式之结构型模式之适配器模式
- 设计模式笔记(7)---适配器模式(结构型)
- 设计模式 一 适配器模式 Adapter(结构型模式)
- 设计模式(6)-结构型-适配器模式(Adapter)(个人笔记)
- 设计模式7——结构型模式之适配器模式
- 设计模式(五)适配器模式Adapter(结构型)
- 白话设计模式 --结构型模式--装饰者(Decorator)模式,适配器模式和外观模式