动态地给一个对象增加一些额外的职责。就增加功能而言,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接口的原因。
因此,如果现在需要加一个功能,我们只需要添加一个功能的装饰子类就可以了,不需要添加其它的子类。它好就好在拥有运行时的灵活性,可以在需要用时随意组合功能,而不需要静态地把各种功能组合写死在代码中。