设计模式系列漫谈之四 - 装饰模式
故事
有一天,小雪的一个小学同学打电话告诉她,老同学马上要结婚了,婚礼将于2月14日举行。由于这个同学长期在外工作,很少联系,现在突然要结婚了,对此,小雪既羡慕又好奇。羡慕的是老同学脸上洋溢的微笑,好奇的是新郎究竟是何方人士。这时老同学给她发短信说,她的老公名叫林郇,在一家外企工作。小雪看到短信后郁闷半天,林郇? [郇]字怎么读啊?为了避免在婚礼上把名叫错,为了避免发生尴尬,小雪突然想起她的手机有语音读短信的功能。于是,她新建一条短信,用手写识别写了这个[郇]字,然后保存,然后打开语音识别选项,加载完成后,打开这条短信,于是,手机读出了这个字为[xun二声],嘿嘿。小雪又突发奇想,近段时间的短信太多了,一天要看好几十次,特别是在开车时读短信息太危险,何不把短信读出来呢?
现在我们必须为小雪解决的问题是: 把追求者发送的短信的同时,能够转换为语音并且读出来(装饰行为)。直接修改各类型手机的具体类,很明显,这种做法不符合设计模式中的"开-闭"原则。
装饰模式(Decorator)的解决方案:
装饰模式的本质在于装饰,为现有的行为“装饰”额外的职责;
装饰模式的实现方式是通过一个抽象类继承被装饰的类或接口,同时聚合该类的实例对象。
短信接口如下:
namespace XiaoXue
{
public interface IMessage
{
void SendMessage(object Msg);
}
}
{
public interface IMessage
{
void SendMessage(object Msg);
}
}
短信具体类如下:
namespace XiaoXue
{
public class NOKIA : IMessage
{
public void SendMessage(object msg)
{
//发送NOKIA短信;
}
}
public class MOTOROLA : IMessage
{
public void SendMessage(object msg)
{
//发送MOTOROLA短信;
}
}
public class SANSUNG : IMessage
{
public void SendMessage(object msg)
{
//发送SANSUNG短信;
}
}
}
{
public class NOKIA : IMessage
{
public void SendMessage(object msg)
{
//发送NOKIA短信;
}
}
public class MOTOROLA : IMessage
{
public void SendMessage(object msg)
{
//发送MOTOROLA短信;
}
}
public class SANSUNG : IMessage
{
public void SendMessage(object msg)
{
//发送SANSUNG短信;
}
}
}
语音接口如下:
namespace XiaoXue
{
public interface ISound
{
void SendSound(object Msg);
}
}
{
public interface ISound
{
void SendSound(object Msg);
}
}
语音具体类如下:
namespace XiaoXue
{
public class NOKIASound : ISound
{
public void SendSound(object msg)
{
//发送NOKIA语音;
}
}
public class MOTOROLASound : ISound
{
public void SendSound(object msg)
{
//发送MOTOROLA语音;
}
}
public class SANSUNGSound : ISound
{
public void SendSound(object msg)
{
//发送SANSUNG语音;
}
}
}
{
public class NOKIASound : ISound
{
public void SendSound(object msg)
{
//发送NOKIA语音;
}
}
public class MOTOROLASound : ISound
{
public void SendSound(object msg)
{
//发送MOTOROLA语音;
}
}
public class SANSUNGSound : ISound
{
public void SendSound(object msg)
{
//发送SANSUNG语音;
}
}
}
装饰类(装饰并继承短信接口)如下:
namespace XiaoXue
{
public abstract class MessageClassDecorator:IMessage
{
private IMessage _messageClass;
public IMessage messageClass
{
get{return _messageClass;}
}
public MessageClassDecorator(IMessage msgClass)
{
_messageClass=msgClass;
}
public virtual void SendMessage(object Msg)
{
_messageClass.SendMessage(Msg);
return;
}
}
}
具体实现类如下:
namespace XiaoXue
{
public class SoundMessageClassDecorator:MessageClassDecorator
{
private ISound _soundClass;
public ISound soundClass
{
get{return _soundClass;}
set{_soundClass=value;}
}
public SoundMessageClassDecorator(IMessage msgClass):base(msgClass)
{
}
public override void SendMessage(object Msg)
{
_soundClass.SendSound(Msg);
base.SendMessage(Msg);
return;
}
}
}
{
public class SoundMessageClassDecorator:MessageClassDecorator
{
private ISound _soundClass;
public ISound soundClass
{
get{return _soundClass;}
set{_soundClass=value;}
}
public SoundMessageClassDecorator(IMessage msgClass):base(msgClass)
{
}
public override void SendMessage(object Msg)
{
_soundClass.SendSound(Msg);
base.SendMessage(Msg);
return;
}
}
}
通过装饰模式,使用Nokia手机的追求者的发送短信的方法如下:
SoundMessageClassDecorator soundMessageClassDecorator=new SoundMessageClassDecorator(new NOKIA());
soundMessageClassDecorator.soundClass=new NOKIASound();
soundMessageClassDecorator.SendMessage("小雪,元旦我们一起出去旅游吧");
soundMessageClassDecorator.soundClass=new NOKIASound();
soundMessageClassDecorator.SendMessage("小雪,元旦我们一起出去旅游吧");