Java设计模式(二十)—— 装饰器模式
装饰器模式定义如下:动态的给对象添加一些额外的职责。就功能来说,装饰器模式相比生成子类更为灵活。
适合装饰器模式的情景如下:
程序希望动态地增强类的某个对象的功能,而又不影响该类的其他对象。
一、问题的提出
在消息日志功能中,接收到的消息可以直接送往屏幕显示,也可以用文件保存。只考虑ILogger的实现类。如下:
public interface ILogger {void log(String msg);
}class ConsoleLogger implements ILogger{@Overridepublic void log(String msg) {System.out.println(msg);}
}class FileLogger implements ILogger{@Overridepublic 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);}@Overridepublic 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");}
}
结果:
可以看到已经将输入的字符串大写并输出到文件中。