小话设计模式(六)适配器模式

来源:互联网 发布:淘宝买同款违法吗 编辑:程序博客网 时间:2024/06/06 00:23

适配器(Adapter)又名包装器(Wrapper),将一个类的接口转换成用户希望的另外一个接口,使得原本接口不兼容的类可以一起工作。

适配器又分为类适配器和对象适配器,而类适配器的实现需要多重继承,而C#并不支持多重继承,所以本文只讨论对象适配器。

假设我们的游戏中有两种类:植物和动物,植物可以被采集,动物有血量可以被攻击(这里简化为被动物攻击,人也是动物的一种嘛),血量低于零死亡。

定义如下:

public class Plant{public virtual void BeCollected(){Console.WriteLine ("Drop seeds");}}public class Animal{public int hp { get; private set;}public int atk {get; private set;}public Animal(){hp = 100;atk = 20;}public void BeAttacked(Animal attacker){if (hp > 0) {hp -= attacker.atk;} if (hp <= 0) {AnimalDead ();}}protected virtual void AnimalDead(){Console.WriteLine ("Drop meat");}}
使用:

Plant plant = new Plant ();plant.BeCollected ();Animal animal = new Animal ();Animal attacker = new Animal ();while (animal.hp > 0) {animal.BeAttacked (attacker);}

这时候策划过来了,对你说,我们需要一种食人花,有血量可以被攻击,也可以攻击别人,但是死亡后掉落种子。

这就很尴尬了,因为一开始并没有考虑到这种情况,为Plant添加hp、atk属性和BeAttacked方法可能并不合适,因为这意味着你要把Animal类里的代码写两遍,这显然不利于维护。而Plant可能本身就继承自其他类,这种情况下也无法让它继承Animal。而且这也违反了接口隔离原则,以及组合/聚合复用原则。

这时候,你可以考虑适配器模式:

public class PiranhaAdapter : Animal{private Plant _plant = new Plant();protected override void AnimalDead(){_plant.BeCollected ();}}

使用:

PiranhaAdapter piranha = new PiranhaAdapter ();while (piranha.hp > 0) {piranha.BeAttacked (attacker);}

这样就似乎很好的解决了食人花的问题。

但是不得不说的是,适配器模式是一种没有办法的办法。如果可能的话,尽量在程序设计之初就考虑到这样的问题,编写出一种更合理的继承关系(例如Plant和Animal都继承自Creature类,Creature里包含血量和攻击力等属性,而Plant里面这两个值都为0)。或者在程序完成度还不高的时候,及时重构。只有在不得已的情况下(例如程序编写已经进入后期,重构代价会很大)才会考虑适配器模式。

适配器模式另外一种用途,就是统一外部API的接口。例如小话设计模式(三)抽象工厂模式中提到的Android和IOS的适配问题,对于AndroidKeyboard和IOSKeyboard这样具体实现接口转换的类,它们本身就是适配器模式的实际应用。

0 0
原创粉丝点击