设计模式复习(十)-------装饰模式

1. 装饰模式的引入

  • 装饰模式以对客户端透明的方式扩展对象的功能,是一种用于替代继承的技术,它通过一种无须定义子类的方式给对象动态增加职责,使用对象之间的关联(组合)关系取代类之间的继承关系
  • 不能过度地使用继承来扩展对象的功能
    • 静态特质,是指如果想要某种功能,必须在编译的时候就要定义这个类,这也是强类型语言的特点;
      • 静态,就是指在编译的时候要确定的东西;
      • 动态,是指运行时确定的东西;----更加灵活
    • 由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性,并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。

动态地给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案。
——《设计模式》GoF

  • 以对客户透明的方式动态地给一个对象附加上更多的职责;
  • 可以在不需要创建更多子类的情况下,让对象的功能得以扩展

2. 装饰模式的结构

在这里插入图片描述

  • 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象—具体构件角色和装饰角色共同的接口。
  • 具体构件(Concrete Component)角色:定义一个将要接收附加责任的类—完成具体业务逻辑。
  • 抽象装饰(Decorator)角色:持有一个构件(Component ->具体构件或具体装饰对象)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(Concrete Decorator)角色:负责给构件对象"贴上"附加的责任。

需要注意的是Decorator和Component的关系,首先是继承关系(这个Is-A关系通常是接口继承,而不是类继承),然后是Decorator里有一个Component的关系(Has-A关系)。拥有这两重关系的优势就是能够组合起来,让它可以不断地扩展,把一个个装饰对象串起来。

抽象构件类典型代码:

abstract class Component
{
    public abstract void Operation();
}

具体构件类典型代码:

class ConcreteComponent : Component
{
    public override void Operation()
    {
        //基本功能实现--与业务逻辑有关
    }
}

抽象装饰类典型代码:

class Decorator : Component{
	private Component component;  //维持一个对抽象构件对象的引用
    
    //注入一个抽象构件类型的对象—也可以使用专门的方法setComponent()
    public Decorator(Component component){
        this.component = component;
    }

    public override void Operation(){
        component.Operation();  //调用原有业务方法
    }
}

具体装饰类典型代码:

class ConcreteDecorator : Decorator{
    public ConcreteDecorator(Component component) : base(component){}
    public override void Operation()  //装饰的顺序可以在此调整
    {
        base.Operation();  //调用原有业务方法—串联所有装饰对象
        AddedBehavior();  //调用新增业务方法
    }
	//新增业务方法    
	public void AddedBehavior() {	
        //功能扩展
    }
}
典型的装饰过程(客户端代码):
 new ConcreteDecorator1(  
    new ConcreteDecorator2(
       new ConcreteDecorator3(
           //最内层的对象最先被调用
          new ConcreteComponent()))).Operation();
顺序:当对最外层的装饰对象调用Operation()函数时,将依次先调用base.Operation()函数,然后才执行本身新增的业务逻辑函数AddedBehavior();因此,最先调用具体构件的Operation()函数,其他装饰对象的Operation()函数将会按照装饰的次序先后被调用到。

3. 装饰模式的总结

  • Decorator模式并非解决“多子类衍生的多继承”问题,Decorator模式,应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。
  • 装饰模式的优点:
    • 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性
    • 通过使用不同的具体装饰类以及这些装饰类的排列组合(内嵌装饰对象的顺序),设计者可以创造出很多不同行为的组合
  • 装饰模式的缺点:
    使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。
  • 装饰模式实现的讨论——简化结构
    大多数情况下,装饰模式的实现都比上面定义中给出的示例的实现要简单。对模式进行简化时需要注意以下的情况:
    • 一个装饰类的接口必须与被装饰类的接口相容。
    • 尽量保持Component作为一个“轻“的类,不要把太多的逻辑和状态放在Component类里。
    • 如果只有一个ConcreteComponent类而没有抽象的Component类(接口),那么Decorator类经常可以是ConcreteComponent的一个子类(合并Component 和ConcreteComponent 角色为一个类)。
    • 示例:PersonFinery

在这里插入图片描述

namespace PersonFinery{
    // 个人信息类--合并了的Component和ConcreteComponent
    class Person{
        public Person(){}

        //被装扮者的姓名
        private string Name;

        public Person(string name){Name = name;}

        //装扮操作--处理具体业务逻辑
        public virtual void Show(){
            Console.Write("{0}的装扮---", Name);
        }
    }
}

namespace PersonFinery{
    // Decrator类--抽象装饰角色
    class Finery:Person{
        ///内嵌的装饰对象--具体的被装饰对象 或 具体的装饰对象
        protected Person component;

        /// 设置被装饰对象 或 具体的装饰对象--即SetComponent()功能
        /// <param name="component">具体的被装饰对象 或 具体的装饰对象</param>
        public void Decorate(Person component){
            this.component = component;
        }
     
        /// 调用内嵌对象实现“装饰”
        
        public override void Show(){
            if (component != null)
                component.Show();
        }
    }
}
namespace PersonFinery{
    // 具体装饰类--大T恤,其他的具体装饰类 类似
    class TShirts:Finery{
        public override void Show()
        {
            base.Show();
            Console.Write("大T恤 ");  //具体装饰
        }
    }
}
namespace PersonFinery{
    class Program{
        static void Main(string[] args)
        {
            Person person = new Person("张三");//最底层被装扮的对象

            Console.WriteLine("\n第1种装扮:");
            //创建装扮对象
            Finery tshirts = new TShirts();
            Finery bigTrouser = new BigTrouser();
            Finery shabbyShoes = new ShabbyShoes();
            //建立装扮链表
            tshirts.Decorate(person);
            bigTrouser.Decorate(tshirts);
            shabbyShoes.Decorate(bigTrouser);
            //层层装扮!
            shabbyShoes.Show();	//这些具体装饰类每次都要调用基类的show方法,当他们串成链后,最先执行的show应该是最先被装饰的那个类,即T恤衫先被打印         

            Console.WriteLine("\n第2种装扮:");
            Finery suit = new Suit();
            Finery neckwear = new Neckwear();
            Finery leatherShoes = new LeatherShoes();
            suit.Decorate(person);
            neckwear.Decorate(suit);
            leatherShoes.Decorate(neckwear);
            leatherShoes.Show();

            Console.Read();
        }
    }
}

执行结果:

第1种装扮:
张三的装扮---大T恤 垮裤 破球鞋
第2种装扮:
张三的装扮---西装 领带 皮鞋

4. 另一个装饰模式的demo

某软件公司基于面向对象技术开发了一套图形界面构件库——VisualComponent,该构件库提供了大量基本构件,如窗体、文本框、列表框等,由于在使用该构件库时,用户经常要求定制一些特殊的显示效果,如带滚动条的窗体、带黑色边框的文本框、既带滚动条又带黑色边框的列表框等等,因此经常需要对该构件库进行扩展以增强其功能。
使用装饰模式来设计该图形界面构件库。

在这里插入图片描述

(1) VisualComponent:抽象界面构件类,抽象构件角色
(2) Window: 窗体类,  具体构件角色
(3) TextBox:文本框类,具体构件角色
(4) ListBox:列表框类,具体构件角色
(5) ComponentDecorator:构件装饰类,抽象装饰角色
(6) ScrollBarDecorator:滚动条装饰类,具体装饰角色
(7) BlackBorderDecorator:黑色边框装饰类,具体装饰角色
(8) Program:客户端程序

在这里插入图片描述

namespace DecoratorSample{
    class ListBox : VisualComponent{
        public override void Display(){
            Console.WriteLine("显示列表框!");}
    }
}
namespace DecoratorSample{
    class TextBox : VisualComponent{
        public override void Display(){
            Console.WriteLine("显示文本框!");}
    }
}
namespace DecoratorSample{
    class Window : VisualComponent{
        public override void Display(){
            Console.WriteLine("显示窗体!");}
    }
}

namespace DecoratorSample{
    // 抽象构件
    abstract class VisualComponent{
        public abstract void Display();
    }
}
namespace DecoratorSample{
    class BlackBorderDecorator : ComponentDecorator{
        public BlackBorderDecorator(VisualComponent component)
            : base(component){}

        public override void Display(){
            base.Display(); //后调用原有功能
            this.SetBlackBorder(); //先加装饰
            //base.Display(); //后调用原有功能
        }

        //实现具体装饰
        public void SetBlackBorder() 
        {
		    Console.WriteLine("为构件增加黑色边框!");
	    }
    }
}
namespace DecoratorSample{
    class ScrollBarDecorator : ComponentDecorator{
        public ScrollBarDecorator(VisualComponent component)
            : base(component){}

        public override void Display(){
            base.Display();  //后调用原有功能
            this.SetScrollBar(); //先加装饰
            //base.Display();  //后调用原有功能
        }

        //实现具体装饰
        public void SetScrollBar() 
        {
		    Console.WriteLine("为构件增加滚动条!");
	    }
    }
}

namespace DecoratorSample{    
    // 抽象Decorator    
    class ComponentDecorator : VisualComponent{
        private VisualComponent component;  //维持对抽象构件类型对象的引用

        //注入抽象构件类型的对象
        public ComponentDecorator(VisualComponent component){
            this.component = component;
        }

        public override void Display(){
            component.Display();
        }
    }
}

namespace DecoratorSample{
    class Program{
        static void Main(string[] args){
            VisualComponent component, componentSB, componentBB; //使用抽象构件定义
            component = new Window(); //定义具体构件
            componentSB = new ScrollBarDecorator(component); //定义装饰后的构件
            componentBB = new BlackBorderDecorator(componentSB); //将装饰了一次之后的对象继续注入到另一个装饰类中,进行第二次装饰
            componentBB.Display();
            Console.Read();
        }
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值