案例分析:设计模式与代码的结构特性

请选择一种我们课程中介绍的设计模式,用您熟悉的编程语言提供一个典型的应用范例,并分析其代码结构特性。完成一篇研究报告,具体要求如下:

  •  引用关键代码(引用代码是为解释说明服务的,不要贴对解释问题无关的代码)解释该设计模式在该应用场景中的适用性;
  •  引入该设计模式后对系统架构和代码结构带来了哪些好处;
  •  解释其中用到的多态机制;
  •  说明模块抽象封装的方法;
  •  分析各个模块的内聚度和模块之间的耦合度;
  •  提供该应用范例完整的源代码包括构建部署的操作过程,建议以github版本库URL的方式提供源代码,其中README.md中说明构建部署的操作过程。

适配器模式

1、适配器模式定义:

    适配器模式可以将一个接口的接口转换成客户希望的另一个接口,让那些接口不兼容的类可以一起工作,是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

2、适配器模式的结构

  类适配器模式结构图:

  

  对象适配器结构图:

    

 

适配器模式包含以下三个角色:

  1:Target(目标抽象类):目标抽象类定义客户所需的接口,可以是一个抽象类或接口,也可以是具体类。在类适配器中,由于C#语言不支持多重继承,所以它只能是接口。

  2:Adapter(适配器类):它可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。它是适配器模式的核心。

  3:Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类包好了客户希望的业务方法。

3、案例分析

本例是一个简单的python实现的适配器模式。

下面是3个不同的类Computer、Human、Synthesizer。

在这里,execute方法是Computer可以执行的主要动作。这一方法由客户端代码调用。

存在的问题是:Computer类仅知道如何调用execute()方法,并不知道Synthesizer中的play()和Human中的speak()方法。

 1 class Computer:
 2     """ 为了尽可能关注于适配器模式,所以这些类都非常简单 """
 3 
 4     def __init__(self, name):
 5         self.name = name
 6 
 7     def __str__(self):
 8         return "The %s computer" % self.name
 9 
10     @staticmethod
11     def execute():
12         return "executes a program"
13 
14 
15 class Human:
16 
17     def __init__(self, name):
18         self.name = name
19 
20     def __str__(self):
21         return "%s the human" % self.name
22 
23     @staticmethod
24     def speak():
25         return "says hello"
26 
27 
28 class Synthesizer:
29 
30     def __init__(self, name):
31         self.name = name
32 
33     def __str__(self):
34         return "the %s synthesizer" % self.name
35 
36     @staticmethod
37     def play():
38         return "is playing an eletronic song"

不改变Synthesizer类和Human类的替代下,使用适配器模式是最好的解决方案。

我们创建一个通用的Adapter类,将一些带不同接口的对象适配到一个统一接口中。_init_()方法的obj参数是我们想要适配的对象,adapted_methods是一个字典,键值对中的键是客户端要调用的方法,值是应该被调用的方法。
 1 class Adapter:
 2     """适配器"""
 3 
 4     def __init__(self, obj: object, adapted_methods: dict):
 5         """ :param obj: 想要适配的对象 :param adapted_methods: 字典, 键值对中的键是客户端要调用的方法, 值是应该被调用的方法。 """
 6         self.obj = obj
 7         # 这里使用了地道的python对象的魔法方法 __dict__ 去为适配对象添加方法         
 8         self.__dict__.update(adapted_methods)
 9 
10     def __str__(self):
11         return str(self.obj)
使用适配器模式的方法:列表objects容纳着所有对象。属于Computer类的可兼容对象不需要适配。可以直接将它们添加到列表中。不兼容的对象则不能直接添加。使用Adapter类来适配它们。结果是,对于所有对象,客户端代码都可以始终调用已知的execute()方法,而无需关心被使用的类之间的任何接口差别。
 1 def main():
 2     objects = [Computer("Dell")]
 3     synth = Synthesizer("moog")
 4     objects.append(Adapter(synth, dict(execute=synth.play)))
 5 
 6     human = Human("Bob")
 7     objects.append(Adapter(human, dict(execute=human.speak)))
 8 
 9     for i in objects:
10         print("{} {}".format(str(i), i.execute()))

结果输出如下:

 可见我们通过适配器实现了在不改变Synthesizer和Human类的前提下客户端的正常运行。

4、适配器模式的优缺点  

优点:可以让任何两个没有关联的类一起运行,提高了类的复用,增加了类的透明度,灵活性好

缺点:过多地使用适配器,会让系统非常零乱,不利于整体把控。

5、适配器模式的适用环境

   系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码

  创建一个可以重复使用的类,用于和一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作

6、源代码地址:

https://github.com/waaq151/DesignPatterns

posted @ 2019-12-08 15:50  waaq  阅读(367)  评论(0)    收藏  举报