装饰者模式:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
下面使用装饰器模式煎饼加码的问题
来看这样一个场景,上班族大多有睡懒觉的习惯,每天早上上班都时间很紧张,于是很多人为了多睡一会儿,就用更方便的方式解决早餐问题,有些人早餐可能会吃煎饼。煎饼中可以加鸡蛋,也可以加香肠,但是不管怎么加码,都还是一个煎饼。再比如,给蛋糕加上一些水果,给房子装修,都是装饰器模式。
首先创建一个煎饼抽象类 Battercake 代码如下:
public abstract class Battercake {
protected abstract String getMsg();
protected abstract double getPrice();
}
创建煎饼基础套餐类(BaseBattercake)继承煎饼抽象类 代码如下:
public class BaseBattercake extends Battercake {
@Override
protected String getMsg() {
return "煎饼";
}
@Override
protected double getPrice() {
return 5;
}
}
创建煎饼基础套餐的扩展抽象装饰类(BattercakeDecorator) 代码如下:
public abstract class BattercakeDecorator extends Battercake{
//静态代理,委派
private Battercake battercake;
public BattercakeDecorator(Battercake battercake){
this.battercake = battercake;
}
@Override
protected String getMsg() {
return this.battercake.getMsg();
}
@Override
protected double getPrice() {
return this.battercake.getPrice();
}
}
创建加鸡蛋套餐的装饰器类(EggDecorator)
public class EggDecorator extends BattercakeDecorator {
public EggDecorator(Battercake battercake) {
super(battercake);
}
@Override
protected String getMsg() {
return super.getMsg() + "+1个鸡蛋";
}
@Override
protected double getPrice() {
return super.getPrice()+1;
}
}
创建加香肠套餐的装饰器类(SausageDecorator)
public class SausageDecorator extends BattercakeDecorator{
public SausageDecorator(Battercake battercake) {
super(battercake);
}
@Override
protected String getMsg() {
return super.getMsg()+"+1个香肠";
}
@Override
protected double getPrice() {
return super.getPrice() + 2;
}
}
测试代码如下:
public class DecoratorTest {
public static void main(String[] args) {
Battercake battercake = null;
//煎饼
battercake = new BaseBattercake();
System.out.println(battercake.getMsg()+ " 总收费:"+battercake.getPrice()+"元");
//加1个鸡蛋
battercake = new EggDecorator(battercake);
System.out.println(battercake.getMsg()+ " 总收费:"+battercake.getPrice()+"元");
//加1个鸡蛋
battercake = new EggDecorator(battercake);
System.out.println(battercake.getMsg()+ " 总收费:"+battercake.getPrice()+"元");
//加1个香肠
battercake = new SausageDecorator(battercake);
System.out.println(battercake.getMsg()+ " 总收费:"+battercake.getPrice()+"元");
}
}
测试结果如下:
与静态代理的最大区别就是职责不同,静态代理注重于功能增强,装饰器更多考虑的是扩展
项目中用到的日志修饰场景 ,假如要把logger日志的输出内容以json的形式输出
未修饰之前的代码如下:
public class JsonLoggerTest {
private static final Logger logger = LoggerFactory.getLogger(JsonLoggerTest.class);
// private static final Logger logger = JsonLoggerFactory.getLogger(JsonLoggerTest.class);
public static void main(String[] args) {
logger.error("错误!");
}
}
结果如下:
过程首先要创建一个Logger的修饰器类(DecoratorLogger) 代码如下:
public class DecoratorLogger implements Logger {
public Logger logger;
public DecoratorLogger(Logger logger){
this.logger = logger;
}
public void error(String s) {
}
public void error(String s, Object o) {
}
@Override
public void error(String s, Object o, Object o1) {
}
...后面方法省略
}
创建具体组件 JsonLogger 代码如下:
public class JsonLogger extends DecoratorLogger {
public JsonLogger(Logger logger) {
super(logger);
}
@Override
public void info(String msg){
JSONObject jsonResult = composeBasicJsonResult();
jsonResult.put("Exception",msg);
logger.info(jsonResult.toJSONString());
}
@Override
public void error(String msg){
JSONObject jsonResult = composeBasicJsonResult();
jsonResult.put("Exception",msg);
logger.error(jsonResult.toJSONString());
}
public void error(Exception e){
JSONObject jsonResult = composeBasicJsonResult();
jsonResult.put("Exception",e);
logger.error(jsonResult.toJSONString());
}
private JSONObject composeBasicJsonResult() {
//拼装了一些运行时的信息
return new JSONObject();
}
}
可以看到,在JsonLogger中,对于Logger的各种接口,我们都用JsonObject对象进行一层封装。在打印的时候,最终还是调用原生接口logger.error(string),只是这个String参数已经被装饰过了。如果有额外的需求,则可以再写一个函数去实现。比如error(Exception e),只传入一个异常对象,这样在调用时就非常方便。另外,为了在新老交替的过程中尽量不改变太多代码和使用方式,笔者又在JsonLogger中加入了一个内部的工厂类JsonLoggerFactory(这个类转移到DecoratorLogger中可能更好一些)。它包含一个静态方法,用于提供对应的JsonLogger实例。最终在新的日志体系中。
JsonLoggerFactory 工厂类代码:
public class JsonLoggerFactory {
public static JsonLogger getLogger(Class<?> clazz){
return new JsonLogger(LoggerFactory.getLogger(clazz));
}
}
??使用修饰后的代码如下:
public class JsonLoggerTest {
// private static final Logger logger = LoggerFactory.getLogger(JsonLoggerTest.class);
private static final Logger logger = JsonLoggerFactory.getLogger(JsonLoggerTest.class);
public static void main(String[] args) {
logger.error("错误!");
}
}
?结果如下:
?
参考:
趣谈装饰器模式,让你一辈子不会忘
设计模式之装饰者模式 - 心中的山水 - 博客园
|