在几年前,有记者问姚明说:在CBA和NBA的最大的区别是什么?姚明的答案是'NBA我需要翻译,而在CBA我不需要。'经过四年的NBA锤炼,他的确是在NBA成长了。不但球技大涨,英语也学得非常棒,用英文答记者问一点问题都没有,不得不令人佩服啊。
姚明刚去美国时,怎么打球呢?什么都听不懂。之前专门为他配备了翻译的,那个翻译一直在姚明身边,特别是比赛场上,教练、队员与他的对话全部是通过翻译来沟通。
适配器模式:讲一个类的接口转换成客户希望的另外一个借口,Adapter模式使得原本由于借口不兼容而不能一起工作的那些类可以一起工作。
适配器模式主要解决什么问题呢?需要的东西就在面前,但却不能使用,而短时间又无法改造它,于是我们就想办法适配他。
姚明不会英语,让姚明立刻会说英语不太可能,让教练和球员会说中文更难办了,那就找个翻译。翻译就是适配器。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Adapter
{
//球员
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 ForeignPlayer
{
//外籍中锋类球员的姓名故意用属性而不是构造方法来区别前三个球员类的不同
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 ForeignPlayer wjzf = new ForeignPlayer();
public Translator(string name)
: base(name)
{
wjzf.Name = name;
}
//翻译者讲Attack翻译为进攻告诉外籍中锋
public override void Attack()
{
wjzf.进攻();
}
//翻译者讲Defense翻译为防守告诉外籍中锋
public override void Defense()
{
wjzf.防守();
}
}
class Program
{
static void Main(string[] args)
{
Player b = new Forwards("巴蒂尔");
b.Attack();
Player m = new Guards("麦克格雷迪");
m.Attack();
//翻译者告诉姚明,教练要求你既要进攻,又要防守。
Player ym = new Translator("姚明");
ym.Attack();
ym.Defense();
Console.Read();
}
}
}
系统的数据和行为都正确,但接口不符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个借口匹配、适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。适配器模式讲了两种类型,类适配器模式和对象适配器模式。主要讲的是对象适配器。
何时使用适配器模式呢?
在想使用一个已经存在的类,但如果它的接口,也就是他的方法和你的要求不相同时,应该考虑适配器模式。
两个类所做的事情相同或相似,但是具有不同的接口时要使用它。客户代码统一调用同一借口就行了。可以更简单,更直接,更紧凑。
要在双方都不太容易修改的时候再使用适配器模式适配。
适配器模式在.Net中应用:DataAdapter用作DataSet和数据源之间的适配器以便检索和保存数据。DataAdapter通过映射Fill(这更改了DataSet中的数据以便与数据源中的数据相匹配)和Update(这更改了数据源中的数据以便与DataSet中的数据相匹配)来提供这一适配器。
适配器模式虽好,却不可乱用。乱用不如不用。
当年,魏文王问名医扁鹊说,你们兄弟三人,都精于医术,到底是哪一位最好呢?扁鹊答:长兄最好,中兄次之,我最差。文王再问:那么为什么你最出名呢?扁鹊答:长兄治病,是治病于病情发作之前。由于一般人不知道他事先能铲除病因,所以他的名气无法传出去。中兄治病,是治病于病情初起时,一般人认为他只能治轻微的小病,所以他的名气只及本乡里。而我是治病于病情严重之时。所以大家以为扁鹊医术最高。
如果能事先预防借口不同的问题,不匹配问题就不会发生,在有小的接口不统一问题发生时,及时重构问题不至于扩大,只有碰到无法改变原有设计和代码的情况时,才考虑匹配。事后控制不如事中控制,事中控制不如事前控制。