1. 代码
1 class adapter:
2 def __init__(self, fun1, fun2):
3 self.fun1 = fun1
4 self.fun2 = fun2
5 def __call__(self, *args, **kwargs):
6 args, kwargs = self.fun1 (*args, **kwargs)
7 self.fun2 (*args, **kwargs)
8
9
10 if __name__ == '__main__':
11 def fun1 (**args):
12 print args['a'], args['b']
13 def fun1_adp (a, b):
14 return (), {'a':a, 'b':b}
15 adp = adapter (fun1_adp, fun1)
16 adp (3, 4)
17
18 def fun2 (a, b):
19 print a, b
20 def fun2_adp (**kwargs):
21 return (kwargs['a'], kwargs['b']), {}
22 adp = adapter (fun2_adp, fun2)
23 adp (b=3, a=5)
2. 功能
-
用来对一些不一致的接口进行适配,从上面的测试代码即可看出来。
3. 使用
编写这个类的原因,是因为我写了一些委托“接口”(算是接口吧),在对模块进行藕合时突然想到,有时我们不太可能提前就把每个模块的委托接口和其它部分调用入口写得一致,比如程序员A喜欢使用字典来传递参数以减少函数参数的个数,程序员B喜欢把必要的参数一一写在函数定义的括号里,假如A写了一个委托接口,B写了一个调用入口:
1 class A:
2 def __init__(self):
3 onChatEvent = delegate (proto='onChatEvent(**kwargs)')
4
5 class B:
6 def display(self, msg):
7 print msg
我们要对A.onChatEvent和B.display进行藕合,怎样才能以最简单的方式实现?
-
方案a:继承B所写的类,增加一个方法display1去调用display,然后对这个新的方法M和A所写的委托接口进行藕合:
1 class BB(B):
2 def display1(self, **kwargs):
3 self.display (args['chat'])
4 a = A()
5 b = BB()
6 a.onChatEvent += b.display1
7 a.onChatEvent (chat='haha')
达到目的了,明确的说我不喜欢这样,因为可能别人已经生成了一个B的实例,强行要人改成BB,不一定都愿意。
-
方案b:实现另一个委托适配器:
1 class A_B_Adapter:
2 def __init__(self):
3 self.onChatEvent = delegate (proto='onChatEvent(msg)')
4 def __call__(self, **kwargs):
5 self.onChatEvent (kwargs['chat'])
6
7 a = A()
8 b = B()
9 adp = A_B_Adapter()
10 a.onChatEvent += adp
11 adp.onChatEvent += b.display
12 a.onChatEvent (chat='haha')
也达到目的了,并且没有把B改成BB这么不爽的事,但写的代码过多。
-
方案c:使用上面的适配器类:
1 def A_B_Adapter(**kwargs):
2 return (kwargs['chat'],), {}
3
4 a = A()
5 b = B()
6 a.onChatEvent += adapter (A_B_Adapter, b.display)
7 a.onChatEvent (chat='haha')
这个比较简单了吧。。。。。
4. 讨论
-
这里的适配器类(adapter)还有委托类(delegate)都是实际项目中需要,才做出来的,对我自己来说非常实用,而且也是实践想法的过程。我编写代码一般尽量少用继承,这个是自己的意识,并不是听了某某大牛说的“由于JAVA的出现,继承被过度使用”(原话可能不是如此)。以前看过QT源码,又看过一些smalltalk介绍的资料,虽然研究不深,但听说这些系统里面,基本是由对象和对像之间发消息来完成的,这对我来说就是一直想看到的。如果系统可以拆成各个独立的模块,单独进行测试,测试完成以后不需要更改(更改可能会带来新问题),就能以非常简单的方式藕合起来,我认为这样的开发过程是最合理不过的了。--LiJie
前面的C++委托类中演示过一个适配器,不过C++写这类功能无法做出一个通用接口,python就有这方面的长处了。