设计模式之装饰器模式

设计模式之装饰器模式 详解

文章目录

一、什么是装饰器模式

装饰器模式(Decorator Pattern) 也称为包装模式(Wrapper Pattern) 是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式。装饰器模式的核心是功能扩展,使用装饰器模式可以透明且动态地扩展类的功能。

二、装饰器模式的角色组成

我们先来看下装饰器模式的通用 类 图:

  • 抽象组件(Component): 可以是一个接口或者抽象类,其充当被装饰类的原始对象,规定了被装饰对象的行为;
  • 具体组件(ConcreteComponent): 实现/继承Component的一个具体对象,也即被装饰对象;
  • 抽象装饰器(Decorator): 通用的装饰ConcreteComponent的装饰器,其内部必然有一个属性指向Component抽象组件;其实现一般是一个抽象类,主要是为了让其子类按照其构造形式传入一个Component抽象组件,这是强制的通用行为(当然,如果系统中逻辑单一,并不需要实现许多装饰器,那么我们可以直接省略该类,而直接实现一个具体装饰器(ComcreteDecorator)即可);
  • 具体装饰器(ConcreteDecorator): Decorator的具体实现类,理论上,每个ConcreteDecorator都扩展了Component对象的一种功能;

三、装饰器模式通用写法示例

  1. 创建一个抽象组件Component来规定被装饰对象的行为
c 复制代码
/**
 * 抽象组件
 *
 * @author zdp
 * @date 2022/9/3 17:48
 */
public abstract class Component {

    public abstract void execute();
}
  • 创建具体组件ConcreteComponent

c 复制代码
/**
 * 具体组件(需要被装饰的组件)
 *
 * @author zdp
 * @date 2022/9/3 17:48
 */
public class ConcreteComponent extends Component {

    @Override
    public void execute() {
        System.out.println("具体组件处理业务逻辑");
    }

}
  • 创建一个抽象装饰器Decorator

c 复制代码
/**
 * 抽象装饰器(继承、实现抽象组件,并持有抽象组件)
 *
 * @author zdp
 * @date 2022/9/3 17:49
 */
public abstract class Decorator extends Component {

    /**
     * 抽象组件
     */
    public Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    /**
     * 将执行动作转发给组件本身执行,可以在转发前后做装饰
     *
     * @author zdp
     * @date   2022/9/3 17:56
     */
    public void execute() {
        component.execute();
    }
}
  • 创建具体装饰器ConcreteDecorator

c 复制代码
/**
 * 抽象装饰器(继承、实现抽象组件,并持有抽象组件)
 *
 * @author zdp
 * @date 2022/9/3 17:49
 */
public abstract class Decorator extends Component {

    /**
     * 抽象组件
     */
    public Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    /**
     * 将执行动作转发给组件本身执行,可以在转发前后做装饰
     *
     * @author zdp
     * @date   2022/9/3 17:56
     */
    public void execute() {
        component.execute();
    }
}
  • 测试

c 复制代码
/**
 * decorator 通用写法测试
 *
 * @author zdp
 * @date 2022/9/3 17:50
 */
public class Test {
    public static void main(String[] args) {
        //创建需要被装饰的组件
        Component component = new ConcreteComponent();
        //给对象透明的增加功能并调用
        Decorator decorator = new ConcreteDecorator(component);
        decorator.execute();
    }
}

四、装饰器模式业务中的 应用 举例

需求:现系统中采用slf4j打印的日志为字符串格式,现使用装饰器模式将日志打印输出为Json格式

现 系统 中的存在Logger接口以及Logger的实现,Logger就可视为抽象组件,Logger的具体实现就为具体组件,现我们只需完成抽象装饰器及具体的装饰器实现即可

  1. 创建抽象装饰器DecoratorLogger
c 复制代码
/**
 * 抽象装饰器,持有并实现抽象组件Logger
 *
 * @author zdp
 * @date 2022/9/3 18:44
 */
public abstract class DecoratorLogger implements Logger {

    protected Logger logger;

    public DecoratorLogger(Logger logger) {
        this.logger = logger;
    }

    @Override
    public void info(String s) { }

    @Override
    public void error(String s) { }

    // 其他实现方法省略....
}
  • 创建具体装饰器JsonLogger

c 复制代码
/**
 * 具体装饰器: Json-logger
 *
 * @author zdp
 * @date 2022/9/3 18:47
 */
public class JsonLogger extends DecoratorLogger {

    public JsonLogger(Logger logger) {
        super(logger);
    }

    @Override
    public void info(String message) {
        JSONObject obj = new JSONObject();
        obj.put("message", message);
        logger.info(obj.toString());
    }

    @Override
    public void error(String message) {
        JSONObject obj = new JSONObject();
        obj.put("message", message);
        logger.error(obj.toString());
    }

}
  • 构造一个Factory

c 复制代码
/**
 * JsonLoggerFactory
 *
 * @author zdp
 * @date 2022/9/4 22:28
 */
public class JsonLoggerFactory {

    public static JsonLogger getLogger(Class<?> clazz){
        return new JsonLogger(LoggerFactory.getLogger(clazz));
    }

}
  • 测试

c 复制代码
/**
 * JsonLogger Test
 * 
 * @author zdp
 * @date 2022/9/3 17:50
 */
public class Test {

    private static final Logger logger = LoggerFactory.getLogger(Test.class);
    private static final Logger jsonLogger = JsonLoggerFactory.getLogger(Test.class);

    public static void main(String[] args) {

        logger.info(" logger info 日志打印....");
        jsonLogger.info(" jsonLogger info 日志打印....");
        System.out.println();
        logger.error("logger error日志打印....");
        jsonLogger.error("jsonLogger error日志打印....");

    }
}

五、装饰器模式优缺点

  • 优点
    • 装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用
    • 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果
    • 装饰器完全遵守开闭原则
  • 缺点
    • 从代码层面来看,使用装饰器模式会出现更多的代码,更多的类,增加程序复杂性
    • 动态装饰时,多层装饰时会更复杂

五、Springboot下使用装饰者模式

c 复制代码
public interface PointsService {
    void addPoints(Long userId, int points);
}


@Service("corePointsService")
public class CorePointsService implements PointsService {
    @Override
    public void addPoints(Long userId, int points) {
        // 核心业务
    }
}

public class LoggingPointsServiceDecorator implements PointsService {

    private final PointsService delegate;

    public LoggingPointsServiceDecorator(PointsService delegate) {
        this.delegate = delegate;
    }

    @Override
    public void addPoints(Long userId, int points) {
        long start = System.currentTimeMillis();
        try {
            delegate.addPoints(userId, points);
        } finally {
            System.out.println("addPoints cost = " + (System.currentTimeMillis() - start));
        }
    }
}


@Configuration
public class PointsServiceConfig {

    @Bean
    @Primary
    public PointsService pointsService(
            @Qualifier("corePointsService") PointsService corePointsService) {
        return new LoggingPointsServiceDecorator(corePointsService);
    }
}
相关推荐
cch89182 小时前
C++、Python与汇编语言终极对比
java·开发语言·jvm
好家伙VCC2 小时前
**InfluxDB实战进阶:基于Golang的高性能时序数据采集与可视化方
java·开发语言·后端·python·golang
斌味代码2 小时前
Java SpringBoot 微服务实战:企业级架构设计与性能调优完全指南
java·spring boot·微服务
好家伙VCC2 小时前
**发散创新:基于Go语言的服务网格实践与流量治理实战**在微服务架构日益复杂的今天,**服务网格(S
java·python·微服务·架构·golang
一定要AK10 小时前
Spring 入门核心笔记
java·笔记·spring
A__tao10 小时前
Elasticsearch Mapping 一键生成 Java 实体类(支持嵌套 + 自动过滤注释)
java·python·elasticsearch
KevinCyao10 小时前
java视频短信接口怎么调用?SpringBoot集成视频短信及回调处理Demo
java·spring boot·音视频
迷藏49410 小时前
**发散创新:基于Rust实现的开源合规权限管理框架设计与实践**在现代软件架构中,**权限控制(RBAC)** 已成为保障
java·开发语言·python·rust·开源
wuxinyan12311 小时前
Java面试题47:一文深入了解Nginx
java·nginx·面试题