虽然目前房价依旧很高,就连我所在的成都郊区(非中心城区)的房价均价都早已破万,但却还是阻挡不了大家对新房的渴望和买房的热情。如果大家买的是清水房,那么无疑还有一项艰巨的任务在等着大家,那就是装修。对新房的装修并没有改变房屋用于居住的本质,但它可以让房子变得更加漂亮和温馨以及更加实用。在软件设计中,也有一种类似于新房装修的技术可以对已有的功能进行扩展使之更加符合用户需求,从而使得对象具有更加强大的功能,这便是本次即将介绍的装饰模式。

装饰模式(Decorator) 学习难度:★★★☆☆ 使用频率:★★★☆☆

一、图形界面构件库设计

1.1 需求背景

背景:M公司开发部基于OO技术开发了一套图形界面构件库Visual Component,该构件库提供了大量的基本构件,如窗体、文本框、列表框等等,由于在使用该构件库时,用户经常要求定制一些特殊的显示效果,例如带滚动条的窗体,带黑色边框的文本框,即带滚动条又带黑色边框的列表框等,因此经常需要对该构件库进行扩展以增强其功能,如下图所示:

  如何提高图形界面构件库的可扩展性并降低其维护成本是M公司开发部的程序猿们必须要面对的一个问题。

1.2 初始设计

  M公司的开发人员针对上面的需求,提出了一个基于继承复用的初始设计方案,其基本结构如下图所示:

  通过分析该设计方案,不难发现存在以下问题:

  (1)系统扩展麻烦,在C#/Java中根本无法实现(不支持多继承)。

  (2)代码重复,不利于对系统进行修改和维护。

  (3)系统庞大,类的数量非常多。

  总之,这个设计不是一个好的设计方案,如何让系统利于扩展又不导致类的数量线性增加呢?让我们了解一下装饰类把。

二、装饰模式概述

2.1 装饰模式简介

  装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为,在现实生活中,这种情况也到处存在,例如一张照片,可以不改变照片本身,给它增加一个相框,使得它具有防潮的功能,而且用户可以根据需要给它增加不同类型的相框,甚至可以在一个小相框的外面再套一个大相框。

装饰(Decorator)模式:动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式远比生成子类实现更加灵活。装饰模式是一种对象结构型模式  

2.2 装饰模式结构

  从结构图中可以看出,装饰模式主要有以下几个角色:

  (1)Component (抽象构件):具体构件和抽象装饰类的基类,声明了在具体构建中实现的业务方法。

  (2)ConcreteComponent(具体构件):抽象构件的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。

  (3)Decorator(抽象装饰类):它也是抽象构件类的子类,用于给具体构件增加职责,但是具体职责在其子类中实现。

  (4)ConcreteDecorator(具体装饰类):抽象装饰类的子类,负责向构件添加新的职责。

三、重构图形界面构件库

3.1 重构后的设计方案

  为了让系统具有更好的灵活性和可扩展性,克服继承复用所带来的问题,M公司开发人员使用装饰模式来重构图形界面库的设计,其中部分类的基本结构如下图所示:

  其中,Component充当抽象构件类,其子类Window、TextBox和ListBox充当具体构件类,ComponentDecorator则充当抽象装饰类,ScrollBarDecorator和BlackBorderDecorator则充当具体装饰类。

3.2 重构后的代码实现

  (1)抽象构件:Component

    /// <summary>/// 抽象界面构件类:抽象构件类/// </summary>public abstract class Component{public abstract void Display();}

  (2)具体构件:Window, TextBox 和 ListBox

    /// <summary>/// 窗体类:具体构件类/// </summary>public class Window : Component{public override void Display(){Console.WriteLine("显示窗体!");}}/// <summary>/// 文本框类:具体构件类/// </summary>public class TextBox : Component{public override void Display(){Console.WriteLine("显示文本框!");}}/// <summary>/// 列表框类:具体构件类/// </summary>public class ListBox : Component{public override void Display(){Console.WriteLine("显示列表框!");}}

  (3)抽象装饰:ComponentDecorator

    /// <summary>/// 构件装饰类:抽象装饰类/// </summary>public class ComponentDecorator : Component{private Component component;public ComponentDecorator (Component component){this.component = component;}public override void Display(){component.Display();}}

  (4)具体装饰:ScrollBarDecorator 和 BlackBorderDecorator

    /// <summary>/// 滚动条装饰类:具体装饰类/// </summary>public class ScrollBarDecorator : ComponentDecorator{public ScrollBarDecorator(Component component) : base(component){}public override void Display(){this.SetScrollBar();base.Display();}public void SetScrollBar(){Console.WriteLine("为构件增加滚动条!");}}/// <summary>/// 黑色边框装饰类:具体装饰类/// </summary>public class BlackBorderDecorator : ComponentDecorator{public BlackBorderDecorator(Component component) : base(component){}public override void Display(){this.SetScrollBar();base.Display();}public void SetScrollBar(){Console.WriteLine("为构件增加黑色边框!");}}

  (5)客户端测试

    public class Program{public static void Main(string[] args){Component component = new Window();// 一次装饰Component componentSB = new ScrollBarDecorator(component);componentSB.Display();Console.WriteLine();// 二次装饰Component componentBB = new BlackBorderDecorator(componentSB);componentBB.Display();Console.ReadKey();}}

  执行后的结果如下图所示:

  

  可以看到,第一次装饰之后,窗体有了滚动条。第二次装饰之后,窗体不仅有了滚动条,还增加了黑色边框。

四、装饰模式小结

4.1 主要优点

  (1)对于扩展一个对象的功能,装饰模式比继承更加灵活 => 不会导致类的个数急剧增加!

  (2)可以对一个对象进行多次装饰,从而创造出很多不同行为的组合 => 得到功能更为强大的对象!

  (3)具体构件类与具体装饰类可以独立变化,可以根据需要增加新的具体构建和具体装饰 => 原有代码无需修改,符合开放封闭原则!

4.2 主要缺点

  虽然装饰模式拱了一种比继承更加灵活机动的方案,但同时也意味着比继承更加易于出错,排错也很困难。特别是经过多次装饰的对象,调试时寻找错误可能需要逐级排查,较为繁琐

4.3 应用场景

  (1)在不影响其他对象的情况下,想要动态地、透明地给单个对象添加职责 => 采用装饰模式吧!

  (2)当不能采用继承的方式对系统进行扩展 或 采取继承不利于系统扩展和维护时 => 采用装饰模式吧!

参考资料

  

  刘伟,《设计模式的艺术—软件开发人员内功修炼之道》

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

转载于:https://www.cnblogs.com/edisonchou/p/7106521.html

设计模式的征途—10.装饰(Decorator)模式相关推荐

  1. 《Head First 设计模式》ch.3 装饰(Decorator)模式

    设计原则 类应该对修改关闭,对扩展开放(开放-关闭原则).在每个地方使用开放-关闭原则是一种浪费,也没有必要,因为这通常会引入新的抽象层次,增加代码复杂度.需要把注意力集中在设计中最有可能改变的地方. ...

  2. 设计模式学习笔记——装饰(Decorator)模式

    设计模式学习笔记--装饰(Decorator)模式 @(设计模式)[设计模式, 装饰模式, decorator] 设计模式学习笔记装饰Decorator模式 基本介绍 装饰案例 类图 实现代码 Dis ...

  3. 设计模式:装饰(Decorator)模式

    设计模式之装饰(Decorator)模式 在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修.相片加相框等.在软件开发过程中,有时想用一些现存的组件.这些组件可能只是完成了一些核心功 ...

  4. Java设计模式之再从[暗黑破坏神装备镶嵌宝石系统]分析装饰(Decorator)模式

    在暗黑破坏神等RPG游戏中,会遇到如下的一些场景:我有一把很普通的武器,我通过给它"注入魔法力量"."镶嵌宝石",来使得它拥有一些攻击特效:例如,一把普通长剑, ...

  5. php设计模式课程---7、装饰器模式如何使用

    php设计模式课程---7.装饰器模式如何使用 一.总结 一句话总结: 装饰器的核心是获取了文章类整个类,而不是获取了文章内容,有了这个文章类,我想给你加多少装饰就给你加多少装饰(将文章这个类封装进去 ...

  6. 吃透设计模式第六篇-装饰者模式

    设计模式的重要性对于程序员来说,相当于盾牌对于美国队长,暴风战斧相对于雷神,内裤对于绿巨人(绿巨人最强武器,手动狗头)来说,是必不可少的. 在此,特别总结下23钟设计模式: 创建型模式:单例模式.抽象 ...

  7. Java进阶专题(八) 设计模式之适配器模式、装饰者模式、观察者模式

    本章节将介绍:三个设计模式,适配器模式.装饰者模式和观察者模式.通过学习适配器模式,可以优雅的解决代码功能的兼容问题.另外有重构需求的人群一定需要掌握装饰者模式.本章节参考资料书籍<Spring ...

  8. 肝一肝设计模式【六】-- 装饰器模式

    系列文章目录 肝一肝设计模式[一]-- 单例模式 传送门 肝一肝设计模式[二]-- 工厂模式 传送门 肝一肝设计模式[三]-- 原型模式 传送门 肝一肝设计模式[四]-- 建造者模式 传送门 肝一肝设 ...

  9. 设计模式 with Python 10:状态模式

    设计模式 with Python 10:状态模式 如果你接触过UML的状态图,应该会对状态图或者状态机有所了解,我们今天讨论的状态模式就是这种设计的落地方案. 和之前的讲解一样,我们从一个具体案例&q ...

最新文章

  1. 域渗透提权之MS14-068
  2. 文巾解题 面试题 03.06. 动物收容所
  3. php写新闻浏览历史,PHP实现浏览历史记录
  4. java中动态顺序死锁问题
  5. Linux下JAVA线程占用CPU高的分析方法
  6. 比特币网站Flexcoin遭黑客攻击 损失极大 被迫关闭
  7. 响应式网站导航html,jQuery和CSS3响应式网站导航幻灯片插件
  8. 抢头条offer机会,抖音面试题:网络编程Socket+GC Roots+数据同步+Redis等
  9. 洛谷P3358 最长k可重区间集问题(费用流)
  10. 视频会议之BigBlueButton
  11. 中国1:100万土壤数据处理
  12. 与黑产作战,揭秘数据黑产起点
  13. 基于java的小型旅游网站设计(含源文件)
  14. 《下学梯航》(全文)
  15. matlab人口增长线性回归拟合_科学网—matlab线性拟合 - 张瑞龙的博文
  16. 文本分类(2)——取特征词构建词典
  17. 使用R读取xls与xlsx文件
  18. PID和TID之间的区别
  19. hibernate4配置c3p0连接池报错
  20. 计算机网络机房需要气体灭火吗,哪些场所需要设置气体灭火系统?

热门文章

  1. Hadoop Hive sql 语法详细解释
  2. 介绍并扩展Fitnesse的测试模块化机制:Scenario
  3. 输入空格hdu - 1010 - Tempter of the Bone
  4. 域用户权限设置目录权限
  5. 如何在Windows Server 2008 Core里面添加Role~~~
  6. github组织存储库使用_为什么我不使用您的GitHub存储库
  7. android5.0后新特性修改标题头,Android5.0中Material Design的新特性
  8. java注解的执行顺序_深入理解Spring的@Order注解和Ordered接口
  9. python socket tcp客户端_python网络编程socketserver模块(实现TCP客户端/服务器)
  10. web前端培训分享:面向对象中类和对象的定义是什么?