【23种设计模式】装饰模式(九)

设计模式,装饰,模式 · 浏览次数 : 338

小编点评

**装饰模式** **英文名称:Decorator Pattern** **定义:** 装饰模式是一种设计模式,它允许在创建对象之前动态添加一些额外的职责。这种模式通过将抽象构件(Component)的实例作为参数传递给具体构件(Concrete Component)对象中,实现对象的扩展。 **核心概念:** * **抽象构件 (Abstract Class):**定义了对象的功能接口,抽象构件可以被多个实现类继承。 * **具体构件 (Concrete Component):**实现抽象构件接口的类,具体实现对象的功能。 * **装饰器 (Decorator):**持有一个构件对象实例,并实现与抽象构件接口一致的接口。 * **装饰 (Decorator):**根据具体需求动态添加对构件对象的附加职责。 **优点:** * **对象功能的扩展:**通过动态添加职责,可以根据需要扩展对象的功能。 * **保持代码可维护性:**通过抽象构件和具体构件,简化了对象的设计。 * **避免扩展功能的增长:**通过动态添加职责,避免了扩展功能的“指数增长”问题。 **缺点:** * **系统复杂性:**装饰模式增加了系统的复杂性,因为需要管理多个构件和装饰器。 * **维护性可能降低:**在添加或移除职责时,需要修改多个类。 * **测试可能困难:**在测试中,需要考虑装饰器的顺序和依赖关系。 **示例:** ```java // 抽象构件接口 abstract class House { abstract void renovation(); } //具体构件类,实现抽象构件接口 class MyHouse implements House { public void renovation() { //装修房子逻辑 } } // 装饰器,实现具体构件接口 class HouseSecurityDecorator implements HouseDecorator { private House house; public HouseSecurityDecorator(House house) { this.house = house; } @Override public void renovation() { // 添加安全系统 house.renovation(); // 打印安全系统信息 } } // 装饰器,实现具体构件接口 class KeepWarmDecorator implements HouseDecorator { private House house; public KeepWarmDecorator(House house) { this.house = house; } @Override public void renovation() { // 添加保温功能 house.renovation(); // 打印保温功能信息 } } ```

正文

前言

装饰模式,英文名称:Decorator Pattern。我第一次看到这个名称想到的是另外一个词语“装修”,我就说说我对“装修”的理解吧,大家一定要看清楚,是“装修”,不是“装饰”。在房子装修的过程中,各种功能可以相互组合,来增加房子的功用。类似的,如果我们在软件系统中,要给某个类型或者对象增加功能,如果使用“继承”的方案来写代码,就会出现子类暴涨的情况。比如:IMarbleStyle是大理石风格的一个功能,IKeepWarm是保温的一个接口定义,IHouseSecurity是房子安全的一个接口,就三个接口来说,House是我们房子,我们的房子要什么功能就实现什么接口,如果房子要的是复合功能,接口不同的组合就有不同的结果,这样就导致我们子类膨胀严重,如果需要在增加功能,子类会成指数增长。

装饰模式的定义

上述的问题的根源在于我们“过度地使用了继承来扩展对象的功能”,由于继承为类型引入的静态特质,所谓静态特质,就是说如果想要某种功能,我们必须在编译的时候就要定义这个类,这也是强类型语言的特点。静态,就是指在编译的时候要确定的东西;动态,是指运行时确定的东西。使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀(多继承)。如何使“对象功能的扩展”能够根据需要来动态(即运行时)地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降为最低?装饰者模式解决此问题应运而生,动态地给一个对象增加一些额外的职责。

装饰模式的组成

  • 抽象构件角色(Component):给出一个抽象接口,以规范准备接收附加责任的对象。

  • 具体构件角色(Concrete Component):定义一个将要接收附加责任的类。

  • 装饰角色(Decorator):持有一个构件(Component)对象的实例,并实现一个与抽象构件接口一致的接口。

  • 具体装饰角色(Concrete Decorator):负责给构件对象添加上附加的责任。
    image

装饰模式的实现

以装修房子为例,完成装饰着模式的代码实现

房子定义
    /// <summary>
    /// 该抽象类就是房子抽象接口的定义,该类型就相当于是Component类型,是饺子馅,需要装饰的,需要包装的
    /// </summary>
    public abstract class House
    {
        /// <summary>
        /// 房子的装修方法--该操作相当于Component类型的Operation方法
        /// </summary>
        public abstract void Renovation();
    }
   /// <summary>
    /// MyHouse的房子,我要按我的要求做房子,相当于ConcreteComponent类型
    /// </summary>
    public sealed class MyHouse : House
    {
        public override void Renovation()
        {
            Console.WriteLine("装修我的房子");
        }
    }
复制
装饰类的定义
 /// <summary>
    /// 该抽象类就是装饰接口的定义,该类型就相当于是Decorator类型,如果需要具体的功能,可以子类化该类型
    /// </summary>
    public abstract class DecorationStrategy : House //关键点之二,体现关系为Is-a,有了这个关系,装饰的类也可以继续装饰了
    {
        //通过组合方式引用Decorator类型,该类型实施具体功能的增加
        //这是关键点之一,包含关系,体现为Has-a
        protected House _house;

        //通过构造器注入,初始化平台实现
        protected DecorationStrategy(House house)
        {
            this._house = house;
        }

        //该方法就相当于Decorator类型的Operation方法
        public override void Renovation()
        {
            if (this._house != null)
            {
                this._house.Renovation();
            }
        }
    }

复制
安全需求类装饰定义
/// <summary>
    /// 具有安全功能的设备,可以提供监视和报警功能,相当于ConcreteDecoratorA类型
    /// </summary>
    public sealed class HouseSecurityDecorator : DecorationStrategy
    {
        public HouseSecurityDecorator(House house) : base(house) { }

        public override void Renovation()
        {
            base.Renovation();
            Console.WriteLine("增加安全系统");
        }
    }
复制
保暖需求类装饰定义
 /// <summary>
    /// 具有保温接口的材料,提供保温功能,相当于ConcreteDecoratorB类型
    /// </summary>
    public sealed class KeepWarmDecorator : DecorationStrategy
    {
        public KeepWarmDecorator(House house) : base(house) { }

        public override void Renovation()
        {
            base.Renovation();
            Console.WriteLine("增加保温的功能");
        }
    }
复制
调用
   public void RunTest()
        {
            //这就是我们需要装饰的房子
            House myselfHouse = new MyHouse();

            DecorationStrategy securityHouse = new HouseSecurityDecorator(myselfHouse);
            securityHouse.Renovation();

            /*
             * 此时房子就有了安全系统了.....
             */

            //【1】如果我既要安全系统又要保暖呢,继续装饰就行
            //DecorationStrategy securityAndWarmHouse = new KeepWarmDecorator(myselfHouse);
            //securityAndWarmHouse.Renovation();


            Console.WriteLine("\r\n*****************************\r\n");

            //【2】如果我既要安全系统又要保暖呢,继续装饰就行【和上边的进行运行比对】
            //【对运行结果难理解的话,打断点单步执行进行理解】

            DecorationStrategy securityAndWarmHouse1 = new KeepWarmDecorator(securityHouse);
            securityAndWarmHouse1.Renovation();
        }
复制

image

装饰模式的优缺点

优点
  • 把抽象接口与其实现解耦。

  • 抽象和实现可以独立扩展,不会影响到对方。

  • 实现细节对客户透明,对用户隐藏了具体实现细节。

缺点
  • 增加了系统的复杂度

与【23种设计模式】装饰模式(九)相似的内容:

【23种设计模式】装饰模式(九)

前言 装饰模式,英文名称:Decorator Pattern。我第一次看到这个名称想到的是另外一个词语“装修”,我就说说我对“装修”的理解吧,大家一定要看清楚,是“装修”,不是“装饰”。在房子装修的过程中,各种功能可以相互组合,来增加房子的功用。类似的,如果我们在软件系统中,要给某个类型或者对象增加

【23种设计模式】适配器模式(六)

## 前言 从今天开始我们开始讲【结构型】设计模式,【结构型】设计模式有如下几种:**适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式、代理模式**。【创建型】的设计模式解决的是对象创建的问题,那【结构型】设计模式解决的是类和对象的组合关系的问题。 今天我们就开始讲【结构型】设计模式里面

【23种设计模式】组合模式(八)

前言 组合模式,英文名称是:Composite Pattern。当我们谈到这个模式的时候,有一个物件和这个模式很像,也符合这个模式要表达的意思,那就是“俄罗斯套娃”。“俄罗斯套娃”就是大的瓷器娃娃里面装着一个小的瓷器娃娃,小的瓷器娃娃里面再装着更小的瓷器娃娃,直到最后一个不能再装更小的瓷器娃娃的那个

【23种设计模式】设计模式综述(开篇)

## 一、设计模式概述: ​ **设计模式(Design pattern)**代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。是一套被反复使用的、多

【23种设计模式】单例模式(一)

## 前言: 单例模式是创建型模式5种中的第1种,**关注对象的创建, 保证一个类仅有一个实例,并且提供一个全局访问点**。在软件系统中,经常有这样一些特殊的类,必须保证它们在系统中只存在一个实例,才能确保它们的逻辑正确性、以及良好的效率。如何绕过常规的构造器,提供一种机制来保证一个类只创建一个实例

【23种设计模式】工厂方法模式(二)

## 前言 在讲述之工厂方法模式前,我们来先了解简单工厂模式,简单工厂模式是最简单的设计模式之一,它虽然不属于GoF的23种设计模式,但是应用也较为频繁,同时它也是学习其他创建型模式的基础。下面我们来先了解下简单工厂模式,然后针对它的缺点来引出工厂方法模式。 ## 简单工厂模式定义 **简单工厂模式

【23种设计模式】抽象工厂模式(三)

## 前言 在抽象工厂模式开篇之前,我们先思考一个问题,如果我们要设计一套房子,其他的组件暂时不考虑,我们仅仅考虑房顶、地板、窗户、房门进行设计。什么样的风格暂时未知,可能会有很多种类。可以先设计一套古典风格的房子,再设计一套现代风格的房子,再设计一套欧式风格的房子....这么多套房子需要设计,需求

【23种设计模式】建造者模式(四)

## 前言 在软件系统中,有时候面临着“一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。如何应对这种变化?如何提供一种“封装机制”来隔离出“复杂对象的各个部分”的变化,从而保持系统中

【23种设计模式】原型模式(五)

## 前言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创建这样的类实例,这就会增加创建类的复杂度和创建过程与客户代码复杂的耦合度。如果采用工厂模式来创建这样的实例对象的话,随着产品类的不断增加,导致子类的数量不断增多,也导致了相

【23种设计模式】桥接模式(七)

## 前言 【**桥接模式**】是【**结构型**】设计模式的第二个模式,也有叫【桥模式】的,英文名称:**Bridge Pattern**。 大家第一次看到这个名称会想到什么呢?我第一次看到这个模式根据名称猜肯定是连接什么东西的。因为桥在我们现实生活中经常是连接着A地和B地,再往后来发展,桥引申为