适配器模式,将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
系统的数据和行为都正确,但接口不符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。
在以下情况下可以考虑使用适配器模式:
- 系统需要复用现有类,而该类的接口不符合系统的需求
- 想要建立一个可重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
- 对于对象适配器模式,在设计里需要改变多个已有子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器,而这不太实际。
C#适配器模式:
namespace 适配器模式 { class Program { static void Main(string[] args) { Player b = new Forwards("巴蒂尔"); b.Attack(); Player m = new Guards("麦克格雷迪"); m.Attack(); //Player ym = new Center("姚明"); Player ym = new Translator("姚明"); ym.Attack(); ym.Defense(); Console.Read(); } } //篮球运动员 abstract class Player { protected string name; public Player(string name) { this.name = name; } public abstract void Attack(); 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); } } //中锋 class Center : Player { public Center(string name) : base(name) { } public override void Attack() { Console.WriteLine("中锋 {0} 进攻", name); } public override void Defense() { Console.WriteLine("中锋 {0} 防守", name); } } //后卫 class Guards : Player { public Guards(string name) : base(name) { } public override void Attack() { Console.WriteLine("后卫 {0} 进攻", name); } public override void Defense() { Console.WriteLine("后卫 {0} 防守", name); } } //外籍中锋 class ForeignCenter { private string name; public string Name { get { return name; } set { name = value; } } public void 进攻() { Console.WriteLine("外籍中锋 {0} 进攻", name); } public void 防守() { Console.WriteLine("外籍中锋 {0} 防守", name); } } //翻译者 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() { wjzf.防守(); } } }
js语言特性的适配器模式:
var googleMap = { show:function(){ console.log('开始渲染谷歌地图'); } }; var baiduMap = { display:function(){ console.log('开始渲染百度地图'); } }; var baiduMapAdapter = { show:function(){ return baiduMap.display(); } }; var renderMap = function(map){ if(map.show instanceof Function){ map.show(); } }; renderMap(googleMap); //输出:开始渲染谷歌地图 renderMap(baiduMapAdapter); //输出:开始渲染百度地图
小结:
- 适配器模式主要用来解决两个已有接口之间不匹配的问题,它不考虑这些接口是怎样实现的,也不考虑它们将来可能会如何演化。适配器模式不需要改变已有的接口,就能够使它们协同作用。
- 装饰者模式和代理模式也不会改变原有的对象的接口,但装饰者模式的作用是为了给对象增加功能。装饰者模式常常形成一条长的装饰链,而适配器模式通常只包装一次。代理模式是为了控制对对象的访问,通常也只包装一次。
- 外观模式的作用倒是和适配器比较相似,有人把外观模式看成一组对象的适配器,但外观模式最显著的特点是定义了一个新的接口。