设计模式のDecoratorPattern(装饰器模式)----结构模式

一、产生背景

装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变现有对象的结构的情况下,动态地将新功能添加到对象中。

在装饰器模式中,有一个基础对象(Component),它定义了需要被装饰的对象的接口。装饰器(Decorator)类实现了与基础对象相同的接口,并且内部含有一个基础对象的实例。装饰器类可以通过在调用基础对象的方法前后添加自己的逻辑来扩展基础对象的功能。

Decorator 的本意是糊裱匠,举个例子,你想要买个苹果,我送你个有圣诞图案的纸包着的苹果,这就是所谓的装饰器模式。

最常见的程序中应用场景:添加日志、性能统计、事物统计、异常处理。

 

遵从:事先处理->真正处理->事后处理 的过程。

 

二、一般做法

“原类抽象,装饰类提供传入接口,对原类的函数扩展重写(并不是语法上,是功能上)”

假设有一部手机你购买来以后只有手机,然后你需要再给其添加一些装饰,比如保护壳,钢化膜或者手机贴画等,这个就是装饰者模式的思想

装饰器模式主要组成部分:

Component:定义一个对象接口,可以给这些对象动态地添加职责

ConcreteComponent:定义一个对象,可以给这个对象添加一些职责

Decorator:维持一个指向Component的指针,并定义一个与Component接口一致的接口

ConcreteDecorator:负责向ConcreteComponent添加功能

在装饰模式中,Decorator定义了一个装饰接口类。因为Decorator与ConcreteComponent继承同一个接口,所以继承Decorator的类ConcreteDecorator可以使用ConcreteComponent的方法,再在ConcreteDecorator里面加入一些新的方法,也就是装饰,就成为了一个包装好的装饰类。

下面是一个基本实现

接口抽象:

    public interface IComponent
    {
        void Operatre();
    }

构建基础功能类:

    public class Component : IComponent 
    {
        public void Operatre() 
        {
            Console.WriteLine("执行基本操作!");      
        }

    }

构建装饰器类:

   public class Decorate : IComponent 
    {

        public IComponent ComponentObj 
        {
            get;
        }

        public Decorate(IComponent component) 
        {
            ComponentObj = component;
        }

        public void Operatre()
        {
            Console.WriteLine("执行前操作!");
            ComponentObj.Operatre();
            Console.WriteLine("执行后操作!");
        }
    }

注意基础对象,不允许外部修改,可以获取查看!

调用:

    internal class Program
    {
        static void Main(string[] args)
        {
            var component = new Component();
            var decorate = new Decorate(component);
            decorate.Operatre();


            Console.ReadLine();
        }
    }

结果:

 

 

 

三、实例

1、抽象基类

public abstract class ProductBase
{
    public abstract string GetName();
    public abstract double GetPrice();
}

2、具体产品

 public class ConcretProuct : ProductBase
    {
        private string _name;
        private double _price;
        public ConcretProuct(string name, double price)
        {
            this._name = name;
            this._price = price;
        }
        public override string GetName()
        {
            return _name;
        }
        public override double GetPrice()
        {
            return _price;
        }
    }

3、装饰

    public class Decorator : ProductBase
    {
        private ProductBase _product = null;
        private string _name;
        private double _price;
        public Decorator(ProductBase product, string name, double price)
        {
            this._product = product;
            this._name = name;
            this._price = price;
        }
        public override string GetName()
        {
            return string.Format("{0},{1}", _product.GetName(), _name);
        }
        public override double GetPrice()
        {
            return _product.GetPrice() + _price;
        }
    }

四、另外一个例子

      我有一个盒子类,有打开和关闭两个函数,我需要记录打开和关闭的时间,那么实现如下。

    public abstract class BaseBox
    {
        public abstract void Open();
        public abstract void Close();
    
    }

    public class SmallBox:BaseBox 
    {

        public override void Open()
        {
            Console.WriteLine("small box open.");
        }

        public override void Close()
        {
            Console.WriteLine("small box close.");
        }
    }

    public class BigBox : BaseBox
    {

        public override void Open()
        {
            Console.WriteLine("big box open.");
        }

        public override void Close()
        {
            Console.WriteLine("big box close.");
        }
    }

    public class BoxDecorator 
    {
        BaseBox _baseBox = null;
        public BoxDecorator(BaseBox box) 
        {
            _baseBox = box;
        }

        public void SetContent(BaseBox box)
        {
            _baseBox = box;
        }

        public void Open() 
        {
            Console.WriteLine(DateTime.Now.ToString());
            _baseBox.Open();
        }

        public void Close() 
        {
            Console.WriteLine(DateTime.Now.ToString());
            _baseBox.Close();
        }

    }




    class Program
    {
        static void Main(string[] args)
        {

            SmallBox small = new SmallBox();
            small.Open();
            small.Close();

            Console.WriteLine("*************");

            BoxDecorator bd = new BoxDecorator(small);
            bd.Open();
            bd.Close();

            Console.WriteLine("*************");

            BigBox big = new BigBox();
            bd.SetContent(big);
            bd.Open();
            bd.Close();

            Console.ReadLine();
        }
    }

 

 

五、设计模式分析

优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。

缺点:多层装饰比较复杂;

           不能满足很多类装饰的需求,如果我有很多商品,商品有不同的分类,那我需要写很多装饰器。

使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。

注意事项:可代替继承。

如果我要多个其他类,要实现不同的处理,那我还可以AOP(面向切面编程aspect oriented programming)实现,其中.Net中RealPoxy提供了这样的能力。

.Net中是反射实现的,其他语言中可以预编译和运行时动态代理实现。

posted @ 2018-03-05 16:36  卖雨伞的小男孩  阅读(165)  评论(0编辑  收藏  举报