当前位置: 首页 > news >正文

深入浅出设计模式——装饰模式(Decorator Pattern)

模式动机

一般有两种方式可以实现给一个类或对象增加行为:
继承机制,使用继承机制是给现有类添加功能的一种有效途径,通过继承一个现有类可以使得子类在拥有自身方法的同时还拥有父类的方法。但是这种方法是静态的,用户不能控制增加行为的方式和时机。
关联机制,即将一个类的对象嵌入另一个对象中,由另一个对象来决定是否调用嵌入对象的行为以便扩展自己的行为,我们称这个嵌入的对象为装饰器(Decorator)。

装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任,换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。这就是装饰模式的模式动机。

模式定义
装饰模式(Decorator Pattern) :动态地给一个对象增加一些额外的职责(Responsibility),就增加对象功能来说,装饰模式比生成子类实现更为灵活。其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合。根据翻译的不同,装饰模式也有人称之为“油漆工模式”,它是一种对象结构型模式。
Decorator Pattern: Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
Frequency of use: medium
UML图

模式结构
装饰模式包含如下角色:
Component: 抽象构件
ConcreteComponent: 具体构件
Decorator: 抽象装饰类
ConcreteDecorator: 具体装饰类

模式分析
与继承关系相比,关联关系的主要优势在于不会破坏类的封装性,而且继承是一种耦合度较大的静态关系,无法在程序运行时动态扩展。在软件开发阶段,关联关系虽然不会比继承关系减少编码量,但是到了软件维护阶段,由于关联关系使系统具有较好的松耦合性,因此使得系统更加容易维护。当然,关联关系的缺点是比继承关系要创建更多的对象。
使用装饰模式来实现扩展比继承更加灵活,它以对客户透明的方式动态地给一个对象附加更多的责任。装饰模式可以在不需要创造更多子类的情况下,将对象的功能加以扩展。

模式实例与解析
穿什么有这么重要?

体系结构

Component: 抽象构件 Component.cs

namespace DecoratorPattern
{
    abstract class Component
    {
        public abstract void Show();
    }
}

ConcreteComponent: 具体构件 Person.cs

using System;

namespace DecoratorPattern
{
    class Person : Component
    {
        public Person()
        { }
        private string name;
        public Person(string name)
        {
            this.name = name;
        }
        public override void Show()
        {
            Console.WriteLine("装扮的 {0}", name);
        }

    }
}

Decorator: 抽象装饰类 Finery.cs

namespace DecoratorPattern
{
    abstract class Finery : Component
    {
        protected Component compoent;
        //打扮
        public void Decorate(Component compoent)
        {
            this.compoent = compoent;
        }
        public override void Show()
        {
            if (compoent != null)
            {
                compoent.Show();
            }
        }
    }
}

ConcreteDecorator: 具体装饰类
BigTrouser.cs

using System;

namespace DecoratorPattern
{
    class BigTrouser : Finery
    {
        public override void Show()
        {
            Console.Write("垮裤");
            base.Show();
        }
    }
}

TShits.cs

using System;

namespace DecoratorPattern
{
    class TShits : Finery
    {
        public override void Show()
        {
            Console.Write("大T恤");
            base.Show();
        }
    }
}

Client:客户类

using System;

namespace DecoratorPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            Person xc = new Person("小菜");
            Console.WriteLine("\n 第一种装扮:");
            BigTrouser bigTourser = new BigTrouser();
            TShits tShits = new TShits();
            bigTourser.Decorate(xc);
            tShits.Decorate(bigTourser);
            tShits.Show();

            Console.WriteLine("\n 第二种装扮:");
            tShits.Decorate(xc);
            bigTourser.Decorate(tShits);
            bigTourser.Show();
            Console.Read();
        }
    }
}

模式优缺点
装饰模式的优点
 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。
 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

装饰模式的缺点
 使用装饰模式进行系统设计时将产生很多小对象,这些对象的区别在于它们之间相互连接的方式有所不同,而不是它们的类或者属性值有所不同,同时还将产生很多具体装饰类。这些装饰类和小对象的产生将增加系统的复杂度,加大学习与理解的难度。
 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

转载于:https://www.cnblogs.com/Bobby0322/p/4191937.html

相关文章:

  • Centos 7.5安装Grafana5.3结合Zabbix3.4实现可视化图形
  • 部分金融常识
  • Python 调用 C 语言 so
  • vue.js 是如何做到数据响应的
  • 计算机科学论文写作5-写硕士论文
  • react native中使用echarts
  • JQuery中$.ajax()方法参数详解
  • 理解 JavaScript Mutation 突变和 PureFunction 纯函数
  • table tr,td,div ... focus
  • 数控切割机造船行业应用
  • 小明的调查作业
  • virtualbox 不能为虚拟电脑打开一个新任务/VT-x features locked or unavailable in MSR.
  • Linux Cluster
  • Mac开发环境配置相关:/usr/include缺失了怎么办?
  • [2019.2.28]BZOJ4033 [HAOI2015]树上染色
  • Angular 2 DI - IoC DI - 1
  • ES学习笔记(10)--ES6中的函数和数组补漏
  • Lsb图片隐写
  • php ci框架整合银盛支付
  • QQ浏览器x5内核的兼容性问题
  • webpack+react项目初体验——记录我的webpack环境配置
  • 阿里云前端周刊 - 第 26 期
  • 基于webpack 的 vue 多页架构
  • 近期前端发展计划
  • 设计模式 开闭原则
  • 问题之ssh中Host key verification failed的解决
  • 应用生命周期终极 DevOps 工具包
  • 完善智慧办公建设,小熊U租获京东数千万元A+轮融资 ...
  • ​业务双活的数据切换思路设计(下)
  • #QT项目实战(天气预报)
  • #我与Java虚拟机的故事#连载17:我的Java技术水平有了一个本质的提升
  • (1) caustics\
  • (6)添加vue-cookie
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (理论篇)httpmoudle和httphandler一览
  • (七)Knockout 创建自定义绑定
  • (十一)图像的罗伯特梯度锐化
  • (五)大数据实战——使用模板虚拟机实现hadoop集群虚拟机克隆及网络相关配置
  • (一)基于IDEA的JAVA基础1
  • .gitignore文件---让git自动忽略指定文件
  • .NET Reactor简单使用教程
  • .NET 表达式计算:Expression Evaluator
  • .NET 反射 Reflect
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • .Net中的集合
  • [17]JAVAEE-HTTP协议
  • [20190401]关于semtimedop函数调用.txt
  • [C++]命名空间等——喵喵要吃C嘎嘎
  • [DevEpxress]GridControl 显示Gif动画
  • [Google Guava] 2.1-不可变集合
  • [Linux]创建新用户并授予root权限
  • [LWC小知识] 标准lightning-input-field怎么取得变更值(onchange)
  • [Mac软件]Adobe XD(Experience Design) v57.1.12.2一个功能强大的原型设计软件
  • [OC]UILabel 文字长的截断方式
  • [python 邮件处理]