写给Python初学者的设计模式入门(1)(3)
装饰器模式
装饰器模式是一个结构性模式,允许我们根据情况,在运行时为一个对象添加新的或附加的行为。
目的是为给一个特定的对象实例应用扩展的函数方法,并且同时也能够产生没有新方法的原对象。它允许多装饰器结合用于一个实例,所以你就不会出现实例同单个装饰器相捆绑的情况了。这个模式是实现子类继承外的一个可选方式,子类继承是指从父类集成相应的功能。与子类继承必须在编译时添加相应的行为不同,装饰器允许你在运行时根据需要添加新的行为。
可以根据以下步骤实现装饰器模式:
-
以原组件类为基类创建装饰器类。
-
在装饰器类中添加一个组件类的指针域
-
将一个组件传递给装饰器类的构造器以初始化组件类指针
-
在装饰器类中,将所有的组件方法指向组件类指针,并且,
-
在装饰器类中,重写每个需要修改功能的组件方法。
相关维基百科http://en.wikipedia.org/wiki/Decorator_pattern)
什么时候使用?
使用装饰器模式的最佳时机是当你有一个根据情况需要添加新的行为的实体时。假设你有一个HTML链接元素,一个登出链接,并且你希望根据当前页面对具体的行为做微小的改动。这种情况下,我们可以使用装饰器模式。
首先,建立我们所需要的装饰模式。
如果我们在主页并且已经登录,那么将登出链接用h2标签标记。
如果我们在不同的页面并且已经登录,那么用下划线标签标记链接
如果已登录,用加粗标记链接。
一旦建立了装饰模式,我们就可以开工了。
- class HtmlLinks():
- def set_html(self, html):
- self.html = html
- def get_html(self):
- return self.html
- def render(self):
- print(self.html)
- class LogoutLink(HtmlLinks):
- def __init__(self):
- self.html = "<a href="logout.html"> Logout </a>"
- class LogoutLinkH2Decorator(HtmlLinks):
- def __init__(self, logout_link):
- self.logout_link = logout_link
- self.set_html(" {0} ".format(self.logout_link.get_html()))
- def call(self, name, args):
- self.logout_link.name(args[0])
- class LogoutLinkUnderlineDecorator(HtmlLinks):
- def __init__(self, logout_link):
- self.logout_link = logout_link
- self.set_html(" {0} ".format(self.logout_link.get_html()))
- def call(self, name, args):
- self.logout_link.name(args[0])
- class LogoutLinkStrongDecorator(HtmlLinks):
- def __init__(self, logout_link):
- self.logout_link = logout_link
- self.set_html("<strong> {0} </strong>".format(self.logout_link.get_html()))
- def call(self, name, args):
- self.logout_link.name(args[0])
- logout_link = LogoutLink()
- is_logged_in = 0
- in_home_page = 0
- if is_logged_in:
- logout_link = LogoutLinkStrongDecorator(logout_link)
- if in_home_page:
- logout_link = LogoutLinkH2Decorator(logout_link)
- else:
- logout_link = LogoutLinkUnderlineDecorator(logout_link)
- logout_link.render()
单例模式
单例模式是一个创建型的设计模式,功能是确保运行时对某个类只存在单个实例对象,并且提供一个全局的访问点来访问这个实例对象。
因为对于调用单例的其他对象而言这个全局唯一的访问点“协调”了对单例对象的访问请求,所以这些调用者看到的单例内变量都将是同一份。
什么时候能够使用?
单例模式可能是最简单的设计模式了,它提供特定类型的唯一对象。为了实现这个目标,你必须控制程序之外的对象生成。一个方便的方法是将一个私有内部类的单个对象作为单例对象。
- class OnlyOne:
- class __OnlyOne:
- def __init__(self, arg):
- self.val = arg
- def __str__(self):
- return repr(self) + self.val
- instance = None
- def __init__(self, arg):
- if not OnlyOne.instance:
- OnlyOne.instance = OnlyOne.__OnlyOne(arg)
- else:
- OnlyOne.instance.val = arg
- def __getattr__(self, name):
- return getattr(self.instance, name)
- x = OnlyOne('sausage')
- print(x)
- y = OnlyOne('eggs')
- print(y)
- z = OnlyOne('spam')
- print(z)
- print(x)
- print(y)
- print(`x`)
- print(`y`)
- print(`z`)
- output = '''
- <__main__.__OnlyOne instance at 0076B7AC>sausage
- <__main__.__OnlyOne instance at 0076B7AC>eggs
- <__main__.__OnlyOne instance at 0076B7AC>spam
- <__main__.__OnlyOne instance at 0076B7AC>spam
- <__main__.__OnlyOne instance at 0076B7AC>spam
- <__main__.OnlyOne instance at 0076C54C>
- <__main__.OnlyOne instance at 0076DAAC>
- <__main__.OnlyOne instance at 0076AA3C>
- '''
因为内置类是用双下划线开始命名,所以它是私有的,用户无法直接访问。内置类包含了所有你希望放在普通类中的方法,并且通过外层包装类的构造器控制其创建。当第一次你创建OnlyOne时,初始化一个实例对象,后面则会忽略创建新实例的请求。
通过代理的方式进行访问,使用__getattr__()方法将所有调用指向单例。你可以从输出看到虽然看起来好像创建了多个对象(OnlyOne),但 __OnlyOne对象只有一个。虽然OnlyOne实例有多个,但他们都是唯一的 __OnlyOne对象的代理。
请注意上面的方法并没有限制你只能创建一个对象,这也是一个创建有限个对象池的技术。然而在那种情况下,你可能会遇到共享池内对象的问题。如果这真是一个问题,那你可以通过为共享对象设计签入“check-in”和迁出“check-out”机制来解决这个问题。
总结
在本文中,我只列举了几个我再编程中觉得十分重要的设计模式来讲,除此之外还有很多设计模式需要学习。如果你对其他的设计模式感兴趣,维基百科的设计模式部分(http://en.wikipedia.org/wiki/Design_pattern_%28computer_science%29)可以提供很多信息。如果还嫌不够,你可以看看四人帮的《设计模式:可复用面向对象软件的基础》(http://www.amazon.com/o/asin/0201633612)一书,此书是关于设计模式的经典之作。
最后一件事:当使用设计模式时,确保你是用来解决正确地问题。正如我之前提到的,设计模式是把双刃剑:如果使用不当,它们会造成潜在的问题;如果使用得当,它们则将是不可或缺的。
译文链接: http://blog.jobbole.com/62023/
评论关闭