1、设计模式(Design Pattern),张凯 副教授 计算机学院 软件工程系,结构模式(Structural Pattern),结构模式结构模式(Structural Pattern)描述如何将类或者对象结合在一起形成更大的结构。结构模式描述两种不同的东西:类与类的实例(即对象)。 根据这一点,结构模式可以分为类的结构模式和对象的结构模式。,结构模式(Structural Pattern),结构模式适配器模式(Adapter) 桥接模式(Bridge) 组合模式(Composite) 装饰模式(Decorator) 外观模式(Facade) 享元模式(Flyweight) 代理模式(Prox
2、y),问题(Problem),在NBA我需要翻译姚明刚来到NBA,身材够高,球技够好 但是英语不是很懂,听不懂教练的战术安排 球员分为前锋、中锋和后卫 教练会给球员分配进攻、防守任务,问题(Problem),问题(Problem),火箭教练的指挥Patrick Patterson, Attack(前锋 帕特里克-帕特森) Terrence Williams, Attack(后卫 泰伦斯-威廉姆斯) Yao Ming,Attack (中锋 姚明),Attack? 要我干啥嘛?,主要内容,适配器模式(Adapter),模式动机模式名称:适配器模式(Adapter) 通常,客户类(client of
3、 class)通过类的接口访问它提供的服务。有时现有的类(existing class )可以提供客户类的功能需要,但是它所提供的接口不一定是客户类所期望的。这是由于现有的接口名称与客户类所查找的不同等诸多不同原因导致的。,适配器模式(Adapter),模式动机在这种情况下, 现有的接口需要转化 (convert) 为客户类期望的接口,这样保证了对现有类的重用。适配器模式(Adapter Pattern)可以完成这样的转化。,适配器模式(Adapter),模式定义 适配器模式(Adapter Pattern): 将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,
4、其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。,适配器模式(Adapter),模式结构,适配器模式(Adapter),模式结构,适配器模式(Adapter),参与者 Target:目标抽象类 Adapter:适配器类 Adaptee:适配者类(被适配) Client:客户类,适配器模式(Adapter),abstract class Player /篮球运动员protected string name;public Player(string name)this.name = name;public abstract void Attack();
5、public abstract void Defense();class Forwards : Player /前锋public Forwards(string name) : base(name)public override void Attack()Console.WriteLine(“前锋 0 进攻“, name);public override void Defense()Console.WriteLine(“前锋 0 防守“, name);,适配器模式(Adapter),class ForeignCenter /外籍中锋private string name;public stri
6、ng Nameget return name; set name = value; public void 进攻()Console.WriteLine(“外籍中锋 0 进攻“, name);public void 防守()Console.WriteLine(“外籍中锋 0 防守“, name);,适配器模式(Adapter),static void Main(string args)Player pp = new Forwards(“Patrick Patterson“);pp.Attack();Player tw = new Guards(“Terrence Williams“);tw.At
7、tack();ForeignCenter ym = new ForeignCenter(“姚明“);ym.进攻();Console.Read();,适配器模式(Adapter),class Translator : Player /翻译者private ForeignCenter wjzf = new ForeignCenter();public Translator(string name) : base(name)wjzf.Name = name;public override void Attack()wjzf.进攻();public override void Defense()wjz
8、f.防守();,适配器模式(Adapter),static void Main(string args)Player pp = new Forwards(“Patrick Patterson“);pp.Attack();Player tw = new Guards(“Terrence Williams“);tw.Attack();Player ym = new Translator (“姚明“);ym.Attack ();Console.Read();,适配器模式(Adapter),例子:系统组件更新问题 现在有一个软件系统,其中有一个组件已经过时,需要从厂商那里引进一个新的组件,但是原系统的
9、组件接口和新组件的接口不同,同时,不想去改变现有的代码,此时如何从旧组件更新到新组件?,这两个接口无法匹配, 系统无法工作,适配器模式(Adapter),适配器模式(Adapter),适配器模式(Adapter),生活中的适配器模式例子,适配器模式(Adapter),例子,简化的鸭子接口和类,interface Duckpublic void quack();public void fly();,适配器模式(Adapter),MallardDuck类(野鸭子),class MallardDuck : Duckpublic void quack()Console.WriteLine(“嘎嘎嘎.“
10、);public void fly()Console.WriteLine(“我在飞哦!“);,适配器模式(Adapter),现在有一种新家伙,interface Turkeypublic void gobble();public void fly();,适配器模式(Adapter),WildTurkey(野火鸡类),class WildTurkey : Turkeypublic void gobble()Console.WriteLine(“咕咕咕.“);public void fly()Console.WriteLine(“我在飞,不过飞不远。“);,适配器模式(Adapter),火鸡适配器
11、,class TurkeyAdapter : DuckTurkey turkey;public TurkeyAdapter(Turkey turkey)this.turkey = turkey;public void quack()turkey.gobble();public void fly()turkey.fly();,适配器模式(Adapter),使用适配器,static void Main(string args)MallardDuck duck = new MallardDuck();WildTurkey turkey = new WildTurkey();Duck turkeyAd
12、apter = new TurkeyAdapter(turkey);turkey.gobble();turkey.fly();testDuck(duck);testDuck(turkeyAdapter);static void testDuck(Duck duck)duck.quack();duck.fly();,适配器模式(Adapter),类适配器和对象适配器,假设我们在软件开发中要记录日志,包括数据库记录日志DatabaseLog和文本文件记录日志WriteLog,适配器模式(Adapter),类适配器和对象适配器,开发过程需要引入一个新的日志接口,但新的日志接口和以前的不一样,适配器模
13、式(Adapter),类适配器,适配器模式(Adapter),类适配器,class DatabaseLogAdapter : DatabaseLog, Ilogpublic void Write()this.WirteLog();class FileLogAdapter : FileLog, Ilogpublic void Write()this.WirteLog();,适配器模式(Adapter),对象适配器,适配器模式(Adapter),对象适配器,class LogAdapter : Ilogprivate Log log;public LogAdapter(Log log)this.l
14、og = log;public void Write()log.WriteLog();,适配器模式(Adapter),上两种适配方式,可以看出在类适配方式中,是通过类的继承来实现的,同时也具有接口ILog的所有行为,这些就违背了面向对象设计原则中的类的单一职责原则,而对象适配器则是通过对象组合的方式来实现的,则符合面向对象的精神,所以推荐用对象适配的模式。,适配器模式(Adapter),适配器模式的优点如下将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。,适配器模式(Adapter),模式使用在以下情况下可以使用适配器模式: 系统需要使用的类的接口不符合系统的要求。 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。这些源类不一定有很复杂的接口。 (对象适配器而言)在设计里,需要改变多个已有子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器,而这不太实际。,Thank You !,