使用场景和原则:
当系统的数据和行为都正确,但接口不符合时,我们应该考虑用适配器。适配器主要应用于希望复用现存的类,但是接口又与复用环境要求的不一致。就是说,两个类所做的事相同或者相似,但是具有不同的接口,这也是一种迫于无奈,双发都不太容易修
改的时候。一般情况下,尽可能的前期不考虑适配器,当然了,如果像对接类似第三方组件之类的,没必要为了它改变自己的接口,那就可以考虑。像我们的 ADO.net里面的 DataAdapter。
案例分析:
姚明去NBA打球,刚到NBA语言不通,这个时候姚明有没有必要迅速学外语呢,答案肯定是否定的。那姚明要怎么跟人沟通?答案是:请一个翻译。照着这个思路,我们画一下类图。
首先,球员的基本动作是Attack和Defense,球员拥有名字。
public abstract class 球员 { protected string name; public 球员 (string name) { this.name = name; } public abstract void Attack(); public abstract void Defense(); }
球员分为三种,前锋,中锋,后卫。
public class 前锋 : 球员 { public 前锋(string name) : base(name) { } public override void Attack() { Console.WriteLine("前锋{0}发起进攻啦", name); } public override void Defense() { Console.WriteLine("前锋{0}立刻防守~", name); } } public class 中锋 : 球员 { public 中锋(string name) : base(name) { } public override void Attack() { Console.WriteLine("中锋{0}发起进攻啦", name); } public override void Defense() { Console.WriteLine("中锋{0}立刻防守~", name); } } public class 后卫 : 球员 { public 后卫(string name) : base(name) { } public override void Attack() { Console.WriteLine("后卫{0}发起进攻啦", name); } public override void Defense() { Console.WriteLine("后卫{0}立刻防守~", name); } }
这个时候来了一个外籍中锋,他拥有的属性和行为都球员基类不一样。
public class 外籍中锋 { string name; public 外籍中锋(string name) { this.name = name; } public void 进攻() { Console.WriteLine("外籍中锋{0}进攻", name); } public void 防守() { Console.WriteLine("外籍中锋{0}防守", name); } }
这个时候,翻译官就可以出来工作了。
public class 翻译官:球员 { private 外籍中锋 w; public 翻译官(string name) : base(name) { w = new 外籍中锋(name); } public override void Attack() { //翻译进攻命令 w.进攻(); } public override void Defense() { //翻译防守命令 w.防守(); } }
最后,如何调用
球员 a=new 前锋("前锋_巴蒂尔"); a.Attack(); //教练直接给翻译官下命令 球员 b = new 翻译官("中锋_姚明"); b.Attack(); b.Defense(); Console.Read();
案例总结:我觉得适配器是一种后期弥补的模式,不能盲目的用。姚明去NBA打球,不需要立刻学会外语,教练通过下命令给翻译官,翻译官转达给姚明,姚明执行命令。其实,这样的做法,必须依赖翻译官,最好方式就是姚明自己会外语,所以,适配器模式不能乱用,就像著名的扁鹊三兄弟的故事,如果前期设计好一点,事前能控制,而不是事后,经常改动。