装饰模式

                                                  装饰模式

          装饰模式:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。

        

结构图

        

         在软件开发过程中,可能经常会根据需要修改扩展对象的功能,如果不采用装饰模式的话,可能会使开发变得非常混乱并且不便于管理。我们先来看一个实例。

有个客户需要开发一个音乐的播放器,于是我们开发出了如下的代码:

public class MusicPlayer
{
    public void Play(string userFilePath)
   {
      if(userFilePath 是音乐文件)
	{
		..........................
		开始播放音乐
		..........................
	}
   }
}

 

public class Program
{
    public static void Main(string[] args)
    {
       MusicPlayer player = new MusicPlayer();
       player.Play(userFile);
    }
}

 

过了半年,程序运行的很稳定,有一天客户需要这个播放器能够放播放视频,为了满足客户的需求,我们开始修改代码。基于开发封闭原则,我们添加一个新的类

public class FilePlayer
{
    public void Play(string userFilePath)
   {
      if(userFile 是音乐文件)
	{
		..........................
		开始播放音乐
		..........................
	}
        else if(userFile 是视频文件)
	{
		..........................
		开始播放视频		
          }
   }
}

过了一年,程序受到了客户的好评,于是很多客户都要求购买,但又都提出了一些各自的要求,客户A要求播放器需要能够播放音乐,视频,还有flash,客户B则只要求能够播放视频和flash,客户C则只要求能够播放音乐和flash,客户D要求只能播放视频......。现在我们该如何开发呢?

如果我们采用继承类或添加新类的方式开发,类会越来越多,而且不好管理。如果了解了装饰模式,那就变的简单了。采用装饰模式代码如下:

    ///<summary>
    /// 简单播放器的统一接口
    /// </summary>
    public interface IPlayer
    {
        void Play(string userFilePath);
    }

    ///<summary>
    /// 装饰器的抽象基类
    /// </summary>
    public abstract class DecoratorPlayer : IPlayer
    {
        protected IPlayer _player = null;
        public DecoratorPlayer(IPlayer player)
        {
            this._player = player;
        }
        public virtual void Play(string userFilePath)
        {
            if (this._player != null)
            {
                this._player.Play(userFilePath);
            }
        }

    }
    ///<summary>
    /// 音乐播放器 
    ///</summary>
    public class MusicPlayer : DecoratorPlayer
    {
        public MusicPlayer(IPlayer play)
            : base(play)
        {

        }

        public override void Play(string userFilePath)
        {
            if (false)
            {
                //播放音乐......
            }
            else
            {
                base.Play(userFilePath);
            }

        }
    }

    ///<summary>
    /// 视频播放器
    /// ///</summary>
    public class VedioPlayer : DecoratorPlayer
    {
        public VedioPlayer(IPlayer play)
            : base(play)
        {
        }

        public override void Play(string userFilePath)
        {
            if (false)
            {
                //播放视频
            }
            else
            {
                base.Play(userFilePath);
            }
        }
    }

    ///<summary>
    /// Flash播放器 
    ///</summary>
    public class FlashPlayer : DecoratorPlayer
    {
        public FlashPlayer(IPlayer play)
            : base(play)
        {
        }

        public override void Play(string userFilePath)
        {
            if (false)
            {
                //播放Flash
            }
            else
            {
                base.Play(userFilePath);
            }
        }
    }


如果采用了装饰模式,我们可以对功能进行任意的组合,列如:

1.只要求能够播放音乐和flash

 static void Main()
        {
 
            MusicPlayer play1 = new MusicPlayer(null);
            VedioPlayer play2 = new VedioPlayer(play1);
            play2.Play("");
        }

2.需要能够播放音乐,视频,还有flash

 static void Main()
        {
            MusicPlayer play1 = new MusicPlayer(null);
            VedioPlayer play2 = new VedioPlayer(play1);
            FlashPlayer play3 = new FlashPlayer(play2);
            play3.Play("");
        }


另外还可以在配置文件中配置对象来完成的装饰步骤,通过公共的配置读取类,通过字典缓存装饰的步骤,然后传入普通的对象,返回装饰后的对象。

配置文件的格式:

<?xml version="1.0" encoding="utf-8" ?>
<Decorator>
<Section>
<Class name="" type="">
<Step name="" type=""/>
<Step name="" type=""/>
<Step name="" type=""/>
</Class>
<Class name="" type="">
<Step name="" type=""/>
<Step name="" type=""/>
<Step name="" type=""/>
</Class>
<Class name="" type="">
<Step name="" type=""/>
<Step name="" type=""/>
<Step name="" type=""/>
</Class>
</Section>
</Decorator>


装饰器步骤构造器代码:

Dictionary<Type, List<IPlayer>> steps = new Dictionary<Type, List<IPlayer>>();
            List<IPlayer> list = steps[typeof(T)];
            foreach (IPlayer item in list)
            {
                play = (T)Activator.CreateInstance(item.GetType(), play);
            }
            return play;


 

适用性

在以下情况下应当使用装饰模式:

1.需要扩展一个类的功能,或给一个类增加附加责任。

2.需要动态地给一个对象增加功能,这些功能可以再动态地撤销。

3.需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实。

总结

Decorator模式采用对象组合而非继承的手法,实现了在运行时动态的扩展对象功能的能力,而且可以根据需要扩展多个功能,避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。同时它很好地符合面向对象设计原则中“优先使用对象组合而非继承”和“开放-封闭”原则。


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值