Decorator装饰模式
动态地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类更为灵活。
——《设计模式》GoF
作用:在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
比如,我们现在想设计一个日志类,记录DB日志(或文本日志),要求能够对日志的优先级 和 错误级别进行记录。
也就是对这个日志类添加了记录错误级别 和 优先级的功能。后续还可能增加其他的功能。
public interface Log {
public void write(String logContent);
}
public class DatabaseLog implements Log{
@Override
public void write(String logContent) {
System.out.println("记录DB-Log:" + logContent);
}
}
public class TextFileLog implements Log{
@Override
public void write(String logContent) {
System.out.println("记录TextFile-Log:" + logContent);
}
}
用于给日志类添加新功能的LogWrapper类:
public abstract class LogWrapper implements Log{
protected Log log;
@Override
public void write(String logContent) {
log.write(logContent);
}
}
public class LogErrorWrapper extends LogWrapper{
private String errorLevel;
public LogErrorWrapper(Log log) {
super();
this.log = log;
}
public String getErrorLevel() {
return errorLevel;
}
public void setErrorLevel(String errorLevel) {
this.errorLevel = errorLevel;
}
@Override
public void write(String logContent) {
logErrorLevel(errorLevel);
super.write(logContent);
}
private void logErrorLevel(String errorLevel) {
System.out.println("错误级别:" + errorLevel);
}
}
public class LogPriorityWrapper extends LogWrapper{
private String priority;
public LogPriorityWrapper(Log log) {
super();
this.log = log;
}
public String getPriority() {
return priority;
}
public void setPriority(String priority) {
this.priority = priority;
}
@Override
public void write(String logContent) {
logPriority(priority);
super.write(logContent);
}
private void logPriority(String priority) {
System.out.println("优先级:" + priority);
}
}
客户端调用:
public class Client {
public static void main(String[] args) {
Log log = new DatabaseLog(); // DB-log
LogErrorWrapper errorWrapper = new LogErrorWrapper(log);// 1级错误级别 DB-log
LogPriorityWrapper priorityWrapper = new LogPriorityWrapper(errorWrapper); // 特别优先 1级错误级别 DB-log
errorWrapper.setErrorLevel("1级错误");
priorityWrapper.setPriority("特别优先");
priorityWrapper.write("Hello World!");
}
}
输出结果:
优先级:特别优先
错误级别:1级错误
记录DB-Log:Hello World!
从上面的代码,我们可以看出,DatabaseLog类只拥有最简单的日志打印功能,而LogWrapper类实现了Log且持有Log的引用,而LogWrapper的子类对Log的功能进行了不同的扩展。而且这些扩展的功能对Log是完全透明的。
从调用处,我们可以看到,在LogWrapper(Decorator)子类的构造器中,我们除了传入Log的子类外,同样可以传入LogWrapper自己的子类,这样装饰的功能就能够进行叠加。这也是为什么我们让Decorator抽象类实现Log接口的原因。
因此,如果现在需要加一个功能,我们只需要添加一个功能的装饰子类就可以了,不需要添加其它的子类。它好就好在拥有运行时的灵活性,可以在需要用时随意组合功能,而不需要静态地把各种功能组合写死在代码中。
Decorator装饰模式的更多相关文章
- C++设计模式-Decorator装饰模式
Decorator装饰模式作用:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活. UML图如下: Component是定义一个对象接口,可以给这些对象动态地添加职责. ...
- c++ 设计模式6 (Decorator 装饰模式)
4. “单一职责”类模式 在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是随着需求的变化,子类急剧膨胀,同时充斥着重复代码,这时候的关键是划清责任. 典型模式代表: Decorato ...
- 设计模式09: Decorator 装饰模式(结构型模式)
Decorator 装饰模式(结构型模式) 子类复子类,子类何其多加入我们需要为游戏中开发一种坦克,除了不同型号的坦克外,我们还希望在不同场合中为其增加以下一种多种功能:比如红外线夜视功能,比如水路两 ...
- 设计模式C++学习笔记之十三(Decorator装饰模式)
装饰模式,动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator模式相比生成子类更为灵活. 13.1.解释 main(),老爸 ISchoolReport,成绩单接口 CFourt ...
- Decorator - 装饰模式
1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继 ...
- 设计模式学习笔记——Decorator装饰模式
装饰模式的作用或动机就是,尽量避免继承,而使用关联.原因是层层继承下来,内容会越来越多,有失控的危险.就扩展性而言,用关联比用继承好.所谓的关联,A使用了B,就叫A关联了B. Component 抽象 ...
- 设计模式学习之路——Decorator装饰模式(结构模式)
子类复子类,子类何其多 假如我们需要为游戏中开发一种坦克,除了各种不同型号的坦克外,我们还希望在不同场合中为其增加以下一种或多种功能:比如红外线夜视功能,比如水陆两栖功能,比如卫星定位功能等等. 动机 ...
- .NET设计模式(10):装饰模式(Decorator Pattern)(转)
概述 在软件系统中,有时候我们会使用继承来扩展对象的功能,但是由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性:并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多 ...
- .NET设计模式(10):装饰模式(Decorator Pattern)
.NET设计模式(10):装饰模式(Decorator Pattern) 装饰模式(Decorator Pattern) --.NET设计模式系列之十 年月..在....对于..由于使用装饰模 ...
随机推荐
- rac 11g_第二个节点重启后无法启动实例:磁盘组dismount问题
原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明以下出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlo ...
- SVG添加链接(转载)
转载地址:http://tech.techweb.com.cn/thread-258715-1-1.html 最基本的交互形式是链接.在 SVG 中,通过一个 <a> 标签提供链接,这与 ...
- 026. asp.net中将图片以二进制方式保存到数据库并以HTTP流方式输出
保存到数据库中 protected void imgbtnCreate_Click(object sender, ImageClickEventArgs e) { string PerHomeName ...
- typeof和instanceof运算符
(1)typeof运算符用于判断某一个变量的数据类型,它可以作为函数来用,如typeof(a)可以返回变量a的数据类型:也可以作为一个运算符来使用,例如typeof a 也可以返回变量a的数据类型,不 ...
- sqlserver 2005列转行
isnull(stuff((select ',' + d.comname from projemp a left outer join emps c on a.empid = c.empidleft ...
- php访问mysql工具类
本文转载自:http://www.cnblogs.com/lida/archive/2011/02/18/1958211.html <?php class mysql { private $db ...
- maven本地仓库的配置以及如何修改默认.m2仓库位置
本地仓库是远程仓库的一个缓冲和子集,当你构建Maven项目的时候,首先会从本地仓库查找资源,如果没有,那么Maven会从远程仓库下载到你本地仓库.这样在你下次使用的时候就不需要从远程下载了.如果你所需 ...
- bzoj3521: [Poi2014]Salad Bar
Description 有一个长度为n的字符串,每一位只会是p或j.你需要取出一个子串S(从左到右或从右到左一个一个取出),使得不管是从左往右还是从右往左取,都保证每时每刻已取出的p的个数不小于j的个 ...
- php base64编码和urlencode
base64编码 加密 base64_encode($str); 解密 base64_decode(base64_encode($str)); urlencode和base64混合使用 functio ...
- Python之Fabric模块
Fabric是基于Python实现的SSH命令行工具,简化了SSH的应用程序部署及系统管理任务,它提供了系统基础的操作组件,可以实现本地或远程shell命令,包括:命令执行.文件上传.下载及完整执行日 ...