装饰器模式定义如下:动态的给对象添加一些额外的职责。就功能来说,装饰器模式相比生成子类更为灵活。
适合装饰器模式的情景如下:
程序希望动态地增强类的某个对象的功能,而又不影响该类的其他对象。
一、问题的提出
在消息日志功能中,接收到的消息可以直接送往屏幕显示,也可以用文件保存。只考虑ILogger的实现类。如下:
public interface ILogger {
void log(String msg);
}
class ConsoleLogger implements ILogger{
@Override
public void log(String msg) {
System.out.println(msg);
}
}
class FileLogger implements ILogger{
@Override
public void log(String msg) {
DataOutputStream dos = null;
try {
dos = new DataOutputStream(new FileOutputStream("d:/log.txt"));
dos.writeBytes(msg+"\r\n");
dos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}现在需求分析提出了新要求,接收到的信息先转化为大写字母或转化为XML文档,然后屏幕显示或日志保存。常规思路是利用派生类实现,增加的类如下表:
| 子类 | 父类 | 功能 |
| UpFileLogger | FileLogger | 转化成大写字母后保存到日志文件中 |
| UpConsoleLogger | ConsoleLogger | 转化成大写字母后屏幕显示 |
| XMLFileLogger | FileLogger | 转化成XML格式后保存到日志文件中 |
| XMLConsoleLogger | ConsoleLogger | 转化成XML格式后屏幕显示 |
如果需求分析继续变化,则类的数目增加非常快,这时就需要用到装饰器模式。
二、装饰器模式
装饰器模式利用包含代替继承,动态地给一个对象添加一些额外的功能。如图:

右半部分是采用装饰器模式后新增的类图,具体代码如下:
(1)抽象装饰器类
由于需求分析变化了,但无论怎么变,它终究还是一个日志类,因此Decorator类要从接口ILogger派生,而成员变量logger表名Decorator对象要对已有的logger对象进行装饰。
public abstract class Decorator implements ILogger{
protected ILogger logger;
public Decorator(ILogger logger) {
this.logger = logger;
}
}
(2)信息大写装饰类
public class UpLogger extends Decorator{
public UpLogger(ILogger logger) {
super(logger);
}
@Override
public void log(String msg) {
//对字符串进行大写“装饰”
msg = msg.toUpperCase();
//然后执行已有的日志功能
logger.log(msg);
}
}(3)测试类
public class Test1 {
public static void main(String[] args) throws InterruptedException {
ILogger existobj = new FileLogger();
ILogger uplogger = new UpLogger(existobj);
uplogger.log("hello zy");
}
}
结果:
可以看到已经将输入的字符串大写并输出到文件中。

版权声明:本文为weixin_49561506原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。