一、引言

在软件开发中,我们经常想要对一类对象添加不同的功能,例如要给手机添加贴膜,手机挂件,手机外壳等,如果此时利用继承来实现的话,就需要定义无数的类,如StickerPhone(贴膜是手机类)、AccessoriesPhone(挂件手机类)等,这样就会导致 ”子类爆炸“问题,为了解决这个问题,我们可以使用装饰者模式来动态地给一个对象添加额外的职责。下面让我们看看装饰者模式。

二、装饰者模式的详细介绍

2.1 定义

装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相比生成子类可以更灵活地增加功能。

具体实现:

/// <summary>
/// 手机抽象类,即装饰者模式中的抽象组件类
/// </summary>
public abstract class Phone
{
public abstract void Print();
} /// <summary>
/// 苹果手机,即装饰着模式中的具体组件类
/// </summary>
public class ApplePhone:Phone
{
/// <summary>
/// 重写基类方法
/// </summary>
public override void Print()
{
Console.WriteLine("开始执行具体的对象——苹果手机");
}
} /// <summary>
/// 装饰抽象类,要让装饰完全取代抽象组件,所以必须继承自Photo
/// </summary>
public abstract class Decorator:Phone
{
private Phone phone; public Decorator(Phone p)
{
this.phone = p;
} public override void Print()
{
if (phone != null)
{
phone.Print();
}
}
} /// <summary>
/// 贴膜,即具体装饰者
/// </summary>
public class Sticker : Decorator
{
public Sticker(Phone p)
: base(p)
{
} public override void Print()
{
base.Print(); // 添加新的行为
AddSticker();
} /// <summary>
/// 新的行为方法
/// </summary>
public void AddSticker()
{
Console.WriteLine("现在苹果手机有贴膜了");
}
} /// <summary>
/// 手机挂件
/// </summary>
public class Accessories : Decorator
{
public Accessories(Phone p)
: base(p)
{
} public override void Print()
{
base.Print(); // 添加新的行为
AddAccessories();
} /// <summary>
/// 新的行为方法
/// </summary>
public void AddAccessories()
{
Console.WriteLine("现在苹果手机有漂亮的挂件了");
}
}

此时客户端调用代码如下:

class Customer
{
static void Main(string[] args)
{
// 我买了个苹果手机
Phone phone = new ApplePhone(); // 现在想贴膜了
Decorator applePhoneWithSticker = new Sticker(phone);
// 扩展贴膜行为
applePhoneWithSticker.Print();
Console.WriteLine("----------------------\n"); // 现在我想有挂件了
Decorator applePhoneWithAccessories = new Accessories(phone);
// 扩展手机挂件行为
applePhoneWithAccessories.Print();
Console.WriteLine("----------------------\n"); // 现在我同时有贴膜和手机挂件了
Sticker sticker = new Sticker(phone);
Accessories applePhoneWithAccessoriesAndSticker = new Accessories(sticker);
applePhoneWithAccessoriesAndSticker.Print();
Console.ReadLine();
}

在装饰者模式中各个角色有:

  • 抽象构件(Phone)角色:给出一个抽象接口,以规范准备接受附加责任的对象。
  • 具体构件(AppPhone)角色:定义一个将要接收附加责任的类。
  • 装饰(Dicorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(Sticker和Accessories)角色:负责给构件对象 ”贴上“附加的责任。

三、装饰者模式的优缺点

看完装饰者模式的详细介绍之后,我们继续分析下它的优缺点。

优点:

  1. 装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活
  2. 通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合
  3. 装饰者模式有很好地可扩展性

缺点:装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。

四、使用场景

下面让我们看看装饰者模式具体在哪些情况下使用,在以下情况下应当使用装饰者模式:

  1. 需要扩展一个类的功能或给一个类增加附加责任。
  2. 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
  3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能

c# 设计模式 之:装饰模式的更多相关文章

  1. 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern)

    原文:乐在其中设计模式(C#) - 装饰模式(Decorator Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 装饰模式(Decorator Pattern) 作者:weba ...

  2. java设计模式之装饰模式

    发现设计模式的学习越来越让自己学习的东西太少了,应该多接触一些东西,多出去走一走. 装饰模式概念: 动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活(大话设计模式) 在不 ...

  3. 【GOF23设计模式】装饰模式

    来源:http://www.bjsxt.com/ 一.[GOF23设计模式]_装饰模式.IO流底层架构.装饰和桥接模式的区别 package com.test.decorator; /** * Com ...

  4. Java——设计模式(装饰模式_IO)

     /* * 装饰设计模式: *  对一组对象的功能进行增强时,就可以使用该模式进行问题的解决; * 装饰和继承都能实现一样的特点:  就是进行功能的扩转增强. * */ public class  ...

  5. .net设计模式之装饰模式

    概述: 装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装饰来包裹真实的对象. 装饰模式的特点: (1) 装饰对象和真实对象有相同的接口.这样 ...

  6. Java IO设计模式(装饰模式与适配器模式)

    01. 装饰模式 1. 定义 Decorator装饰器,就是动态地给一个对象添加一些额外的职责,动态扩展,和下面继承(静态扩展)的比较.因此,装饰器模式具有如下的特征: 它必须持有一个被装饰的对象(作 ...

  7. 【Unity与23种设计模式】装饰模式(Decorator)

    GoF中定义: "动态地附加额外的责任给一个对象.装饰模式提供了一个灵活的选择,让子类可以用来扩展功能." 装饰模式一般用来增加新功能 它可以避免更改已经实现的程序代码 从而增加系 ...

  8. C 设计模式:装饰模式

    最近在公司分享了下C语言版的设计模式,记录一下吧. 参考:<设计模式之禅>中“装饰模式”章节. 上面书中是用C++来实现的,我使用了书中的例子,改用C语言来实现. 一.基础知识 面向对象最 ...

  9. 从零开始单排学设计模式「装饰模式」黑铁 I

    阅读本文大概需要 3.6 分钟. 本篇是设计模式系列的第四篇,虽然之前也写过相应的文章,但是因为种种原因后来断掉了,而且发现之前写的内容也很渣,不够系统. 所以现在打算重写,加上距离现在也有一段时间了 ...

  10. 设计模式之装饰模式,session共享的底层原理

    前言 还记得当初写spring-session实现分布式集群session的共享的时候,里面有说到利用filter和HttpServletRequestWrapper可以定制自己的getSession ...

随机推荐

  1. Android 开发工具类 13_ SaxService

    网络 xml 解析方式 package com.example.dashu_saxxml; import java.io.IOException; import java.io.InputStream ...

  2. Kubernetes+Flannel 环境中部署HBase集群

    2015-12-14注:加入新节点不更改运行节点参数需求已满足,将在后续文章中陆续总结. 注:目前方案不满足加入新节点(master节点或regionserver节点)而不更改已运行节点的参数的需求, ...

  3. filebeat output redis 报错 i/o timeout

    filebeat output  redis 报错 i/o timeout 先把报错内容贴出来. ERROR redis/client. go: Failed to RPUSH to redis li ...

  4. Dubbo2.7源码分析-Dubbo是如何整合spring-framework的

    这篇文章是Dubbo源码分析的开端,与其说这篇文章是Dubbo源码分析,不如是spring源码分析,因为大部分都是在分析spring如何解析xml配置文件的,为了与后面的Dubbo源码分析保持一致,姑 ...

  5. [WC 2018]州区划分

    Description 题库链接 小 \(S\) 现在拥有 \(n\) 座城市,第 \(i\) 座城市的人口为 \(w_i\) ,城市与城市之间可能有双向道路相连. 现在小 \(S\) 要将这 \(n ...

  6. cordova打包APK,报错:Cannot evaluate module CordovaLib : Configuration with name 'debug' not found.

    原因:之前做其他项目的时候把环境(gradle)升级了. 解决方案:将gradle降低回原来的版本.

  7. 云存储(Swift+Keystone)部署策略

    Swift是OpenStack的对象存储模块,Keystone是OpenStack的权限验证模块.可以于这两个模块搭建一个较为完善的云存储系统. 1.官方方案 云存储的服务器分三种类型: 验证节点 A ...

  8. 【原】戏说Java

    戏说Java 本文只是个人闲余之际写的,查阅了些许资料,仅当娱乐.如有雷同,纯属巧合.   如果要学好一个东西,就应该要把他拟人化,当做一个你的好朋友,对他产生兴趣,那么你自然而然就会学习好他了.俗话 ...

  9. iOS调用系统页面中文显示

    在开发的过程中,我们会接入很多的sdk,比如相机,相册,是否允许获取位置等,大多数的情况下是默认显示英文, 在plist文件里面添加一个key就可以了,如下图: key:Localization na ...

  10. 招新系统(jsp+servlet,实现简略前端网页注册登录+后台增删改查,分学生和管理员,Java语言,mysql数据库连接,tomcat服务器)

    生活不只是眼前的苟且,还有诗和远方. 架构说明: 要求是采用MVC模式,所以分了下面的几个包,但是由于是第一次写,可能分的也不是很清楚: 这个是后台部分的架构: 这个是前端的的展示: (那个StuLo ...