设计模式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上,一方 ...
随机推荐
- eclipse 中xml文件的字体改不了
XML Editor的改不了. 修改colors & fonts里的eclipse中打开window->prefece->generation-basic 下 Text Edito ...
- dxjk中 支付宝二维码支付 git 存疑
线上的vendor/latrell/alipay 文件拉取不了至本地,失去了git监控 要想本地使用 1.注释掉config/app.php 'providers' 下的Latrell模块 2.下载线 ...
- Goclipse on Eclipse
Goclipse插件安装地址 https://goclipse.github.io/releases gocode.godef都可以通过Download快速安装 但guru容易失败:package g ...
- HTTP重要概念
connection连接 一个传输层的实际环流,它是建立在两个相互通讯的应用程序之间. 在http1.1,request和reponse头中都有可能出现一个connection的头,此header的含 ...
- GOF23设计模式之单例模式(singleton)
一.单例模式概述 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点. 由于单例模式只生成一个实例,减少了系统性能开销.所以当一个对象的产生需要比较多的资源时,如读取配置.产生其他依赖对象时, ...
- 求n对括号的合法组合
一道经典的面试题,求n对括号有多少种合法的组合. 抽象为2n个位置,每个位置可以有2种取值,总共有2^2n个组合,附加约束条件是要符合括号的语法,用来剪枝. 括号语法的合法性条件: 初始化左括号和右括 ...
- Models-详细操作
# 单表简单查询13种方法 1.all(): 查询所有结果 all: models.表名.objects.all() book_all=models.Book.objects.all() # 结果是q ...
- VS2012编译Lua5.3.1
编译静态库: 1.新建Win32控制台应用程序Lua5.3,下一步,应用程序类型选择:DLL,空项目,完成. 2.项目名右键属性,配置属性--项目默认值--配置类型:静态库(.lib) 3.头文件上右 ...
- BurpSuite—-Sequencer模块(定序器)
一.简介 Burp Sequencer是一种用于分析数据项的一个样本中的随机性质量的工具.你可以用它来测试应用程序的session tokens(会话tokens)或其他重要数据项的本意是不可预测的, ...
- Betsy's Tour 漫游小镇(dfs)
Description 一个正方形的镇区分为 N2 个小方块(1 <= N <= 7).农场位于方格的左上角,集市位于左下角.贝茜穿过小镇,从左上角走到左下角,刚好经过每个方格一次.当 N ...