Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4971852
  • 博文数量: 921
  • 博客积分: 16037
  • 博客等级: 上将
  • 技术积分: 8469
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-05 02:08
文章分类

全部博文(921)

文章存档

2020年(1)

2019年(3)

2018年(3)

2017年(6)

2016年(47)

2015年(72)

2014年(25)

2013年(72)

2012年(125)

2011年(182)

2010年(42)

2009年(14)

2008年(85)

2007年(89)

2006年(155)

分类: Python/Ruby

2013-12-19 11:15:33


  1. #! /usr/bin/env python
  2. #coding=utf-8

  3. ###适配器
  4. from zope.component import adapts
  5. from zope.interface import implements, Interface, Attribute

  6. class IDesk(Interface):
  7.     """A frontdesk will register object's details"""
  8.     
  9.     def register():
  10.         """Register object's details"""
  11.         
  12. class IGuest(Interface):
  13.     name = Attribute("Name of guest")
  14.     place= Attribute("Place of guest")

  15. class Guest(object):
  16.     implements(IGuest)
  17.     def __init__(self, name, place):
  18.         self.name = name
  19.         self.place = place
  20.         
  21. class FrontDeskNG(object):
  22.     #对应 IDesk 的适配器
  23.     implements(IDesk) #实现接口
  24.     
  25.     #适配器适用于IGuest对象
  26.     adapts(IGuest)
  27.     def __init__(self, guest):
  28.         self.guest = guest
  29.         
  30.     def register(self):
  31.         guest = self.guest
  32.         next_id = get_next_id()
  33.         bookings_db[next_id] = {
  34.             'name' : guest.name,
  35.             'place': guest.place,
  36.             'phone': guest.phone
  37.         }
  38.         
  39. jack = Guest("Jack", "Bangalore")

  40. #jack_frontdesk = FrontDeskNG(jack)

  41. #被xx适配
  42. #print IDesk.providedBy(jack_frontdesk)

  43. #使用适配器组件之前,必须在组件注册表中注册该适配器

  44. #在使用一个适配器组件之前,你必须在一个也被称作站点管理器的组件注册表中注册该适配器。
  45. #通常情况下,站点管理器是属于一个站点的。站点和站点管理器在开发Zope 3应用的时候会更重要,
  46. #现在你只需要了解全局站点和全局站点管理器(或者叫组件注册表)就可以了。
  47. #全局站点管理器是保存在内存之中,而局部站点管理器是持久化的。

  48. #在注册组件之前,首先需要获得全局站点管理器:
  49. from zope.component import getGlobalSiteManager
  50. gsm = getGlobalSiteManager()

  51. #适配器注册成组件,需要调用组件注册表的 registerAdapter 方法。
  52. #第一个参数是适配器的类或者工厂
  53. #第二个参数是一个由多个适配者(adaptee 也就是适配器所适配的对象)所组成的tuple
  54. #第三个参数是由该适配器组件所实现的接口
  55. #第四个参数是个可选参数,提供了该适配器的名称
  56. #如果给出了适配器名称,那么该适配器就是一个已命名适配器,如果没有给出适配器名称,
  57. #那么该参数默认为一个空字符串( ''
  58. #注:
  59. gsm.registerAdapter(FrontDeskNG, (IGuest,), IDesk, 'ng')

  60. #上面的组件注册流程中,我们给出了适配者(adaptee)的接口和适配器所提供的接口,
  61. # 不过由于在适配器的实现中已经给定了这些细节,注册的时候完全没有必要再次指定这些参数,
  62. # 事实上,我们完全可以像下面这样注册这个适配器:

  63. gsm.registerAdapter(FrontDeskNG, name='ng')

  64. #局部组件是持久化组件,而全局组件是保存在内存之中。
  65. #全局组件是根据应用的设置进行注册的,
  66. #而局部组件是在应用启动的时候从数据库中加载到内存的。

  67. #查询适配器
  68. from zope.component import getAdapter, queryAdapter
  69. #从组件注册表中获取已注册的组件是通过 zope.component 包中的两个函数来完成的。
  70. #一个是 getAdapter 另一个是 queryAdapter 。两个函数都接受相同的参数,
  71. #不过如果无法找到组件,那么 getAdapter 会抛出 ComponentLookupError ,
  72. #而 queryAdapter 会返回 None 。

  73. #在上一节中,我们以'ng'为名字注册了一个组件,这个组件提供了 IDesk 接口,
  74. #并且适配于房客对象(适配者 adaptee)。

  75. #下面就是如何获取一个既适配于 jack 对象的接口( IGuest ),
  76. #又提供了 IDesk 接口,同时被命名为 ng 的组件的例子。
  77. #在这里, getAdapter 和 queryAdapter 的作用是一致的:

  78. print getAdapter(jack, IDesk, 'ng')

  79. print queryAdapter(jack, IDesk, 'ng')

  80. #第一个参数是适配者(adaptee),然后是组件应该提供的接口,最后是适配器组件的名字。

  81. #如果我们试图查找一个有相同的接口和适配者(adaptee)但是使用一个没有被注册过的名字的组件,
  82. #那么查询会失败

  83. #print getAdapter(jack, IDesk, 'not-exists')
  84. print queryAdapter(jack, IDesk, 'not-exists')

  85. #在查找失败的时候,getAdapter 抛出一个 ComponentLookupError 异常,
  86. #而 queryAdapter 返回 None

  87. #第三个参数,也就是组件的注册名,是可选项。如果没有提供第三个参数,
  88. #那么这个参数默认为空字符串。由于之前我们没有用空字符串注册组件,
  89. #getAdapter 会抛出 ComponentLookupError ,类似的,
  90. #queryAdapter 会返回 None

  91. print queryAdapter(jack, IDesk)

  92. ##在这一节中,我们学习了如何注册一个简单适配器和如何从组件注册表中获取这个适配器。
  93. ##这类适配器被称为简单适配器是因为它只适配于一个适配者(adaptee)。
  94. ##如果一个适配器适配于多个适配者(adaptee),那么这个适配器被称为多重适配器。

  95. ####**利用接口来获取适配器

  96. #我们可以利用接口来直接获取适配器,不过这种方式只能获取未命名简单适配器。
  97. #第一个参数是适配者(adaptee),第二个参数是一个关键字参数,
  98. #如果适配器查找失败,那么就会返回第二个参数:

  99. print IDesk(jack, alternate='default-output')
  100. print IDesk(jack, 'default-output')

  101. #如果没有给出第二个参数,那么会抛出 TypeError
  102. #print IDesk(jack)
  103. #下面我们采用无命名方式来注册 FrontDeskNG:

  104. gsm.registerAdapter(FrontDeskNG)

  105. print "xxxxxxxx"
  106. print IDesk(jack)

  107. ###4.5适配器模式
  108. ##在Zope组件架构中的适配器概念和《设计模式》一书中的经典 适配器模式 是非常类似的;
  109. #但是,ZCA中的适配器的设计应用目标要比 适配器模式 广泛的多。
  110. # 适配器模式的目的是把一个类的接口转换为客户需要的另一个接口,
  111. # 这可以使得本来不兼容的几个类在一起工作。但是在《设计模式》一书中的“设计动机”一节中,
  112. # GoF提到:“通常情况下,适配器需要负责提供适配类没有提供的功能”。
  113. # ZCA的适配器更多的着眼于为适配对象(适配者 adaptee)增加功能而不是创建新的接口。
  114. # ZCA的适配器允许适配器类对象通过增加方法的方式来扩展功能

  115. #但是在下面一句话中,我使用了“适配对象”来替代“适配类”。
  116. #这是因为GoF在书中描述了根据实现不同区分的两种适配器,一种是 类适配器
  117. #另一种则是 对象适配器 。类适配器采用多重继承来把一个接口适配为另外一个,
  118. #而对象适配器依赖于对象组合来完成适配。

  119. #ZCA的适配器采用了对象适配器模式,并且采用委托(delegation)模式作为组合机制。
  120. #GoF的面向对象设计第二原则就是:“倾向于对象组合而不是类继承”.

  121. #ZCA适配器的主要优势就是在于明确组件的接口和组件注册表。
  122. #ZCA的适配器组件都在组件注册表中进行过注册,客户对象可以在需要的时候根据名字和接口来查找这些适配器。

阅读(1451) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~