C#设计模式学习2——适配器模式
适配器模式
在实际开发过程中,我们经常遇到这样的事情,我们根据初步的需求制定了一个基类,在开发过程中才了解到详细的需求或者需求发生了变动。而开发工作中的接口早已经定义完毕,并已经大规模投入编码。此时若改动接口的定义会造成很多编码上重复性的修改工作,并进而有可能造成修改不完全而导致的语义错误或逻辑错误。语义错误尚可以在编译阶段发现,而一旦发生逻辑性的错误,后果将会非常严重,甚至足以导致系统崩溃。此时就需要用到适配器模式的设计方法。
适配器模式主要应用于,当接口里定义的方法无法满足客户的需求,或者说接口里定义的方法的名称或者方法界面与客户需求有冲突的情况。
适配器模式的使用方法:
用一个类同时继承接口和已知类,利用已知类中定义的方法和属性等,实现接口中的定义(主要利用了重载接口方法的办法)。用此类作为其他业务类的基类,也就是这个类适配了接口和已知类。若已知类发生变化,只需修改类适配器,就可以满足接口的实现。
具体示例如下(代码均采用书中的代码,某些代码可能进行了简化)。
有定义好的接口如下:
{
float GetMass();
float GetThrust();
void SetSimTime(float f);
}
实际需要的已知类如此定义:
{
PhysicalRocket(float burnArea, float burnRate, float fuelMass, float totalMass);
public float GetBurnTime()
{
}
public float GetMass(float f)
{
}
public float GetThrust(float f)
{
}
}
此时,实际需要的已知类和已经定义的接口是有差别的,此时我们就需要一个适配器类来适配已知类和接口。
{
private float _time;
public OozinozRocket(float burnArea, float burnRate, float fuelMass, float totlMass) : base(burnArea, burnRate, fuelMass, totlMass)
{
}
public float GetMass()
{
return base.GetMass(this._time);
}
public float GetThrust()
{
return base.GetThrust(this._time);
}
public void SetSimTime(f time)
{
this._time = time;
}
}
接口也就是定义了一套固定的行为。适配器模式就是实现了此类接口,并能够提供客户所需服务的类的子类。此类适配器模式称为类适配器。
当没有定义客户接口的时候,我们也可以使用适配器模式,这类适配器叫“对象适配器”。与类适配器不同的是,它不是继承已知类,而是将已知类作为类的成员变量,实例化一个已知类的对象,利用此对象的方法来实现适配。
上面的例子将用下面的方式实现。Skyrocket类是OozinozSkyrocket要遵守的行为类,不是定义的接口。
{
protect float _simTime;
public Skyrocket(float mass, float thrust, float burnTime)
{
}
float GetMass()
{
}
float GetThrust()
{
}
void SetSimTime(float f)
{
}
}
此时,需要的对象适配器如下:
{
private PhysicalRocket _rocket;
public OozinozSkyrocket(PhysicalRocket r) : base(r.GetMass(0), r.GetThrust(0), r.GetBurnTime())
{
this._rocket = r;
}
public float GetMass()
{
return this._rocket.GetMass(base._simTime);
}
public float GetThrust()
{
return this._rocket.GetThrust(base._simTime);
}
}
类适配器相对于对象适配器的优势在于:
类适配器是定义了接口规范的,而对象适配器的规范类一旦发生变化(定义方法内部的改变),可能导致运行时出错。
Difficulty of making decision depends on what to lose not gain