九.结构型设计模式——Adapter Pattern(适配器模式)

  • 定义

  将一个接口转换成客户想要的另一个接口,适配器模式使接口不兼容的那些类可以一起工作。

  UML类图如下:

  

  其中类的定义及关系如下:  

  1. Target(目标抽象类):定义客户要用的特定领域的接口。

  2. Adapter(适配器-公接口):调用另一个接口,作为一个转换器。

  3. Adaptee(适配器-母接口):定义一个接口,Adapter需要接入。

  4. Clinet(客户调用类):协同对象符合Adapter适配器。

  典型应用的顺序图如下,客户的提交消息被传到Adaptee中。

  

  • 实例1:化学数据银行

  化学药品对象通过适配器接口访问化学数据银行。类图如下:

  

  

代码
//目标抽象类
class ChemicalCompound
{
protected string name;
protected float boilingPoint;
protected float meltingPoint;
protected double molecularWeight;
protected string molecularFormula;
//构造函数
public ChemicalCompound(string name)
{
this.name = name;
}
//属性
public float BoilingPoint
{
get { return boilingPoint; }
}
public float MeltingPoint
{
get { return meltingPoint; }
}
public double MolecularWeight
{
get { return molecularWeight; }
}
public string MolecularFormula
{
get { return molecularFormula; }
}
}

//公接口
class Compound : ChemicalCompound
{
private ChemicalDataBank bank;
public Compound(string name)
:
base(name)
{
//适配器(母接口)-化学数据银行
bank = new ChemicalDataBank();
boilingPoint
= bank.GetCriticalPoint(name, "B");
meltingPoint
= bank.GetCriticalPoint(name, "M");
molecularFormula
= bank.GetMolecularStructure(name);
molecularWeight
= bank.GetMolecularWeight(name);
}
public void Display()
{
Console.WriteLine(
"\n化合物:{0}--------", name);
Console.WriteLine(
" 分子式:{0}", MolecularFormula);
Console.WriteLine(
" 分子量:{0}", MolecularWeight);
Console.WriteLine(
" 熔点:{0}", MeltingPoint);
Console.WriteLine(
" 沸点:{0}", BoilingPoint);
}
}

//适配器(母接口)-化学数据银行
class ChemicalDataBank
{
//取得临界点
public float GetCriticalPoint(string compound,string point)
{
float temperature=0.0F;
if(point=="M")//临界点
{
switch(compound.ToLower())
{
case "water":
temperature
=0.0F;
break;
case "benzene":
temperature
=5.5F;
break;
case "alcohol":
temperature
=-114.1F;
break;
}
}
else//沸点
{
switch(compound.ToLower())
{
case "water":
temperature
=100.0F;
break;
case "benzene":
temperature
=80.1F;
break;
case "alcohol":
temperature
=78.3F;
break;
}
}
return temperature;
}
//取得分子式
public string GetMolecularStructure(string compound)
{
string structure="";
switch(compound.ToLower())
{
case "water":
structure
="H2O";
break;
case "benzene":
structure
="C6H6";
break;
case "alcohol":
structure
="C2H6O2";
break;
}
return structure;
}
//取得分子量
public double GetMolecularWeight(string compound)
{
double weight=0.0;
switch(compound.ToLower())
{
case "water":
weight
=18.015;
break;
case "benzene":
weight
=78.1134;
break;
case "alcohol":
weight
=46.0688;
break;
}
return weight;
}
}

//客户应用测试
class Client
{
[STAThread]
static void Main(string[] args)
{
//显示取得水的特性
Compound water = new Compound("Water");
water.Display();
//显示取得苯的特性
Compound benzene = new Compound("Benzene");
benzene.Display();
//显示取得乙醇的特性
Compound alcohol = new Compound("Alcohol");
alcohol.Display();
Console.Read();

}
}
  •  实例2:清洁系统

  例如有个清洁系统已经设计完成,但你想增加更多的工作,IExtra接口就是采用Adapter模式插入系统中的,类图如下:

  

  

代码
//假定系统原来已定义Clean接口
public interface IClean
{
void MakeClean();
}
//Office类,实现Clean接口
public class Office:IClean
{
public void MakeClean()
{
Console.WriteLine(
"清洁办公室");
}
}
//WorkShop类,实现Clean接口
public class WorkShop:IClean
{
public void MakeClean()
{
Console.WriteLine(
"清洁工作室");
}
}

//IExtra接口扩展了Clean接口
public interface IExtra : IClean
{
void TakeCare();
}

//Facility设备类实现了IExtra接口,除了清洁还要养护
public class Facility:IExtra
{
public void MakeClean()
{
Console.WriteLine(
"清洁设备");
}
public void TakeCare()
{
Console.WriteLine(
"养护照料");
}
}

//客户应用测试
class Client
{
[STAThread]
static void Main(string[] args)
{
IExtra e
= new Facility();
e.MakeClean();
e.TakeCare();

IClean c
= new Office();
c.MakeClean();

c
= new WorkShop();
c.MakeClean();
Console.Read();
}
}

 

 

  • 优势和缺陷

  适配器模式可以将一个类的接口和另一个类的接口匹配起来,使用的前提是你不能或不想修改原来的适配器母接口(adaptee)。例如,你向第三方购买了一些类、控件,但是没有源程序,这时,使用适配器模式,你可以统一对象访问接口。但客户调用可能需要变动。

  • 应用情景

  下面的情景很适合应用适配器模式:

  1. 对象需要利用现存的并且接口不兼容的类。

  2. 你需要创建可重用的类以协作其他接口不一定兼容的类。

  3. 你需要使用若干个现存的子类但又不想派生这些子类的每一个接口。

posted on 2010-11-01 21:31  tLEE  阅读(790)  评论(0编辑  收藏  举报

导航