姓名:高振松
学号:07770116
1、生活场景:看过美国科幻片的同学应该都会为美国人那惊人的想象力说折服吧。在美国的科幻片里有一种东西会经常在镜头里出现,那就是会飞行的交通工具(汽车,卡车之类的)。这些交通工具既可以在陆地上跑,也可以在天空中飞行或者在水中行驶。现假设,现在有一家汽车生产商,最近突破一项关键技术,使得所有类型的车辆都可以在天空中飞或者在水中行驶的功能。而你正好在给该生产商开发系统软件,现在要实现对所有车辆的模拟,你该如何进行编写。
2、我在这里展示我的不假思索的解决方案:
我记得在以前上面向对象的编程语言课时,老师在讲解类的继承特性时提到使用类的继承可以来扩展类的功能。在一般直觉下,我首先想到的是用类的继承关系来模拟上述问题。
类图如下: 私家车可以飞,卡车则可以在水中行驶。
实现代码:
私家车的基本功能:
public class _FutureCar
{
public virtual string OperateA()
{
return "小型私家车在陆地上以一档速度行驶。";
}
public virtual string OperateB()
{
return "小型私家车在陆地上以二档速度行驶。";
}
public virtual string OperateC()
{
return "小型私家车在陆地上以三档速度行驶。";
}
}
私家车的扩展功能:
public class _FlyableFutureCar : _FutureCar
{
public override string OperateA()
{
string strDo = base.OperateA();
strDo += "\n 在启动飞行功能在空中飞行!";
return strDo;
}
public override string OperateB()
{
string strDo = base.OperateB();
strDo += "\n 在启动飞行功能在空中飞行!";
return strDo;
}
public override string OperateC()
{
string strDo = base.OperateC();
strDo += "\n 在启动飞行功能在空中飞行!";
return strDo;
}
}
卡车的基本功能:
public class _FutureTruck
{
public virtual string OperateA()
{
return "大卡车在陆地上以一档速度拉货。";
}
public virtual string OperateB()
{
return "大卡车在陆地上以二档速度拉货。";
}
public virtual string OperateC()
{
return "大卡车在陆地上以三档速度拉货。";
}
}
卡车的扩展功能:
public class _DriveInWaterFutureTruck : _FutureTruck
{
public override string OperateA()
{
string strDo = base.OperateA();
strDo += "\n 在启动水中行驶功能在水中行驶!";
return strDo;
}
public override string OperateB()
{
string strDo = base.OperateB();
strDo += "\n 在启动水中行驶功能在水中行驶!";
return strDo;
}
public override string OperateC()
{
string strDo = base.OperateC();
strDo += "\n 在启动水中行驶功能在水中行驶!";
return strDo;
}
}
3、现在就让我们开探讨下这种方案中的缺陷。
情形一: 如果生产商要生产可以在水中行驶的Car,和可以在空中飞行的卡车,则该怎么改代码?在这里唯一的方式则是添加新的类 DriveInWaterCar ,和 FlyableTruck。
这里的车辆和扩展类。功能还比较少,要是10种类型的车辆和10种类型的扩展功能的话,进行组合将可能会产生110个。
情形二:如果要动态地添加车辆和功能的话,将这样改代码?在这个情形中,按照继承的方式,删除的功能,只需要删除派生类即可。要是删除车辆的一个类别(如Truck),则要删除大量的代码,删除_FutureTruck, 及其派生类_DriveInWaterFutureTruck, FlyableTruck。对于添加,存在相同问题。也就是说,用一般的继承关系来处理上述问题,存在扩展不够开放问题。

4、归纳阶段
下面是我用装饰模式来解决类继承带来的缺陷。
在这展示装饰模式之前,我们先了解装饰模式的目的或者是其所针对的问题。
首先,装饰(Decorator)模式又名包装(Wrapper)模式[GOF95]。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。注意,装饰模式是继承关系的一个替代方案,实现与继承关系相同的效果。
其次,装饰模式,只是以对客户透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。就像西游记里的孙猴子一样,任它72变变来变去,本质上还是个猢狲。
5、验证阶段
好的,现在让我们来看看装饰模式是否解决了之前不假思索的缺陷。
2.扩展不够开放问题。由于装饰模式中,装饰类(FlyComponent或者DriveInWaterComponent)只是引用了被装饰类(FutureCar或者FutureTruck),同样对扩展也开放。添加一个新的被装饰类,不用被装饰类继承就可以被装饰。添加一个装饰类,不用继承被装饰类,就可以进行装饰被装饰类。
相关代码:
接口IComponent:
public interface IComponent
{
string OperateA();
string OperateB();
string OperateC();
}
被装饰类FutureCar 和 FutureTruck:
public class FutureTruck : IComponent
{
#region IComponent 成员
public string OperateA()
{
return "大卡车在陆地上以一档速度在拉货。";
}
public string OperateB()
{
return "大卡车在陆地上以二档速度在拉货。";
}
public string OperateC()
{
return "大卡车在陆地上以三档速度在拉货。";
}
#endregion
}
public class FutureCar : IComponent
{
#region IComponent 成员
public string OperateA()
{
return "小型私家车在陆地上以一档速度行驶。";
}
public string OperateB()
{
return "小型私家车在陆地上以二档速度行驶。";
}
public string OperateC()
{
return "小型私家车在陆地上以三档速度行驶。";
}
#endregion
}
装饰类:
public abstract class Decorate : IComponent
{
protected IComponent m_COM = null;
public abstract IComponent Component
{
set;
}
#region IComponent 成员
public abstract string OperateA();
public abstract string OperateB();
public abstract string OperateC();
#endregion
}
被装饰类:
public class FlyComponent : Decorate
{
public override IComponent Component
{
set
{
if (value is FutureCar)
{
base.m_COM = value;
}
else
{
throw new Exception("Component 不是 FutureCar类型!");
}
}
}
public override string OperateA()
{
string strDo = base.m_COM.OperateA();
strDo += "\n 在启动飞行功能在空中飞行!";
return strDo;
}
public override string OperateB()
{
string strDo = base.m_COM.OperateB();
strDo += "\n 在启动飞行功能在空中飞行!";
return strDo;
}
public override string OperateC()
{
string strDo = base.m_COM.OperateC();
strDo += "\n 在启动飞行功能在空中飞行!";
return strDo;
}
}
public class DriveInWaterComponent : Decorate
{
public override IComponent Component
{
set
{
if (value is FutureTruck)
{
base.m_COM = value;
}
else
{
throw new Exception("Component 不是 FutureTruck类型!");
}
}
}
public override string OperateA()
{
string strDo = base.m_COM.OperateA();
strDo += "\n 在启动水中行驶功能在水中行驶!";
return strDo;
}
public override string OperateB()
{
string strDo = base.m_COM.OperateB();
strDo += "\n 在启动水中行驶功能在水中行驶!";
return strDo;
}
public override string OperateC()
{
string strDo = base.m_COM.OperateC();
strDo += "\n 在启动水中行驶功能在水中行驶!";
return strDo;
}
}