设计模式09: Decorator 装饰模式(结构型模式)
Decorator 装饰模式(结构型模式)
子类复子类,子类何其多
加入我们需要为游戏中开发一种坦克,除了不同型号的坦克外,我们还希望在不同场合中为其增加以下一种多种功能:比如红外线夜视功能,比如水路两栖功能,比如卫星定位功能等等。
问题代码:
/// <summary>
/// 抽象坦克
/// </summary>
public abstract class Tank
{
public abstract void Shot();
public abstract void Run();
}
//各种型号
public class T50 : Tank
{
public override void Shot()
{
//...
} public override void Run()
{
//...
}
} public class T75 : Tank
{
public override void Shot()
{
//...
} public override void Run()
{
//...
}
}
/// <summary>
/// 红外线夜视
/// </summary>
public interface IA
{
//...
}
/// <summary>
/// 水陆两栖
/// </summary>
public interface IB
{
//...
}
//各种不同功能组合
public class T50A : T50, IA
{
//...
} public class T50B : T50, IB
{
//...
} public class T50AB : T50,IA,IB
{
//...
}
动机(Motivation)
上述描述的问题根源在于我们“过度的使用继承来扩展对象的功能”,由于继承为类引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类组合(扩展功能的组合)会导致更多子类的膨胀(多继承)。
如何使“对象功能的扩展”能够根据需求来动态地(运行时)实现?同时避免“扩展功能增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降为最低?
意图(Intent)
动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活。——《实际模式》GoF
实例代码:
/// <summary>
/// 抽象坦克
/// </summary>
public abstract class Tank
{
public abstract void Shot();
public abstract void Run();
}
//各种型号
public class T50 : Tank
{
public override void Shot()
{
//...
} public override void Run()
{
//...
}
} public class T75 : Tank
{
public override void Shot()
{
//...
} public override void Run()
{
//...
}
}
public abstract class Decorator : Tank//接口继承,抽象类可以看做接口
{
private Tank tank;//Has-A对象组合 public Decorator(Tank tank)
{
this.tank = tank;
} public override void Shot()
{
tank.Shot();
} public override void Run()
{
tank.Run();
}
}
/// <summary>
/// 红外功能扩展
/// </summary>
public class DecoratorA : Decorator
{
public DecoratorA(Tank tank):base(tank)
{
}
public override void Shot()
{
//红外功能扩展
//do shot...
base.Shot();
} public override void Run()
{
//红外功能扩展
//do run...
base.Run();
}
}
/// <summary>
/// 水陆两栖功能扩展
/// </summary>
public class DecoratorB : Decorator
{
public DecoratorB(Tank tank):base(tank)
{
}
public override void Shot()
{
//水陆两栖功能扩展
//do shot...
base.Shot();
} public override void Run()
{
//水陆两栖功能扩展
//do run...
base.Run();
}
}
class App
{
public static void Main()
{
Tank tank=new T50();
DecoratorA da = new DecoratorA(tank);//红外功能扩展
DecoratorB db = new DecoratorB(da);//红外、水陆两栖功能扩展
}
}
Decorator模式的几个要点
- 通过采用组合,而非继承的手法,Decorator模式实现了在运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了单独使用继承带来的“灵活性差”和“多子类衍生问题”。
- Tank类在Decorator模式中充当抽象接口的角色,不应该去实现具体的行为。而且Decorator类对于Tank类应该是透明——换言之Tank类无需知道Decorator,Decorator类是从外部来扩展Tank类的功能。
- Decorator类在接口上表现为is-a Tank类的继承关系,即Decorator继承了Tank类所具有的接口。在实现上又表现为has-a Tank的组合关系,即Decorator类又使用了另一个Tank类。我们可以使用一个或者多个Decorator对象来“装饰”一个Tank对象,而且装饰后的对象仍然是Tank对象。
- Decorator模式并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。
设计模式09: Decorator 装饰模式(结构型模式)的更多相关文章
- NET设计模式 第三部分 结构型模式(7):适配器模式(Adapter Pattern)
适配器模式(Adapter Pattern) ——.NET设计模式系列之八 Terrylee,2006年2月 概述 在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但 ...
- Java设计模式(9)——结构型模式之装饰模式(Decorator)
一.概述 动态地给一个对象添加一些额外的职责.就增加功能来说, Decorator模式相比生成子类更为灵活.该模式以对客 户端透明的方式扩展对象的功能. UML简图 角色 在持有Component的引 ...
- 设计模式学习之装饰者模式(Decorator,结构型模式)(16)
参考地址:http://www.cnblogs.com/zhili/p/DecoratorPattern.html 一.定义:装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任,装饰者模式相 ...
- Java设计模式06:常用设计模式之适配器模式(结构型模式)
1. Java之适配器模式(Adapter Pattern) (1)概述: 将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类,可以在一起 ...
- Java设计模式(13)——结构型模式之桥梁模式(Bridge)
一.概述 概念 将抽象与实现脱耦,使得抽象和实现可以独立运行 UML图 角色: 角色关系 二.实践 按照上面的角色建立相应的类 抽象化角色 /** * 抽象化角色 * * @author Admini ...
- Java设计模式(12)——结构型模式之门面模式(Facade)
一.概述 概念 简要示意图(没有一个统一的UML图) 角色 门面角色:门面模式核心,它被客户端调用,并且熟悉子系统 子系统角色:子系统,子系统并不知道门面的存在,门面对它来说只不过是另外一个客户端 ...
- Java设计模式(11)——结构型模式之享元模式(Flyweight)
一.概述 概念 避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类). UML简图 单纯享元模式 角色 抽象享元角色(Flyweight):定义享元子类公共接口 具体享元角色(Co ...
- Java设计模式(8)——结构型模式之组合模式(Composite)
一.概述 定义 将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性. 简图 角色——对应上图中顶点为Component,左边为Leaf,右边为C ...
- Java设计模式(10)——结构型模式之代理模式(Proxy)
一.概述 概念 UML简图 实际使用的场景示例 如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待 ...
- Java设计模式(7)——结构型模式之适配器模式(Adapter)
一.概述 概念 其实,举个生活中的例子的话,适配器模式可以类比转接头,比如typeC和USB的转接头,把原本只能接typeC的接口,拓展为可以接普通USB:这里的转接头一方面需要查在typeC上,一方 ...
随机推荐
- 一次在局域网中ssh连接的尝试
最近到手一台二手HP笔记本.卖我本子的是以为很漂亮的服装设计师,她因为有了一台新的Mac本所以HP本就闲置了,于是就卖给了我.本子性能跟我自己的三星本差不多,除了电池不太给力,每次开机都会提示601. ...
- 一键获取 所有连接过的WIFI密码
使用方法 一.运行CMD (以及 开启无线网卡.最好是笔记本) 二.输入命令: for /f "skip=9 tokens=1,2 delims=:" %i in ('netsh ...
- Spring Cloud Eureka 注册,发布,调用服务
Spring Cloud为服务治理做了一层抽象接口,所以在Spring Cloud应用中可以支持多种不同的服务治理框架,如Netflix Eureka.Consul和Zookeeper.在Spring ...
- 小程序App方法
App() 注册一个小程序 小程序的入口方法 //app.js App({ onLaunch: function(options) { console.log("onLaunch" ...
- Oracle 利用执行计划来避免排序操作
在oracle中,利用index来避免排序 SQL) NOT NULL); SQL> CREATE INDEX IND_T_NOSORT_NAME ON T_NOSORT(NAME); SQL& ...
- win7系统程序未响应怎么办
问题描述:出现“程序未响应...”而后系统程序就没有反应了. 解决方案:1.运行→输入“regedit”→hkey_current_usser/control panel/desktop/window ...
- leetcode454
public class Solution { public int FourSumCount(int[] A, int[] B, int[] C, int[] D) { var dic = new ...
- Java微信公众平台开发(五)--文本及图文消息回复的实现
转自:http://www.cuiyongzhi.com/post/43.html 上篇我们说到回复消息可以根据是否需要上传文件到微信服务器可划分为[普通消息]和[多媒体消息],这里我们来讲述普通消息 ...
- 搭建Easyui环境在Myeclipse或Eclipse中
转自:https://www.cnblogs.com/henuyuxiang/p/4283018.html 1.下载Easyui.网址:http://www.jeasyui.com/download/ ...
- Apple Ad Hoc
Apple Ad Hoc 发布测试 App只能通过Ad Hoc分享给绑定我们账号的设备上,所以至是一百台 1.官网member Center创建Ad Hoc证书 2.在官网下载Ad Hoc证书到mac ...