【装饰器】设计模式:灵活的替代继承方案

简介

在面向对象编程中,装饰器设计模式提供了一种动态添加功能的方法,而无需改变对象本身的结构。这种模式通过创建一个包含原有对象的封装对象来扩展其行为,从而避免了多重继承的复杂性。

核心组件

  • 组件接口(Component):定义了对象的接口,可以给这些对象动态地添加职责;
  • 具体组件(Concrete Component):定义了将要接收附加责任的对象;
  • 装饰器(Decorator):持有一个组件对象的引用,并定义一个与组件接口一致的接口;
  • 具体装饰器(Concrete Decorator):负责给组件添加新的责任;

工作原理

装饰器模式通过创建一个装饰器类,它包含一个组件对象的引用,并在装饰器类中实现组件接口。具体装饰器类通过扩展装饰器类来为组件对象添加新的行为。

使用场景

装饰器模式适用于以下场景:

  • 需要扩展功能:当需要为对象动态添加额外的功能时;
  • 替代继承:作为一种替代多重继承的方式,以避免继承层次的复杂性;
  • 运行时添加功能:在运行时根据需要添加功能,而不是在编译时确定。

构建一个灵活的日志记录系统

创建一个基本的日志记录器,并允许通过装饰器动态地添加额外的日志记录功能,如日志级别过滤,日志格式化日志持久化

基本组件
// 日志记录器接口
public interface Logger {
    void log(String message);
}

// 基本日志记录器实现
public class ConsoleLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("LOG: " + message);
    }
}
装饰器抽象类

创建一个装饰器抽象类,它持有一个 Logger 对象的引用,并实现 Logger 接口。

// 日志记录器装饰器抽象类
public abstract class LoggerDecorator implements Logger {
    protected final Logger decoratedLogger;

    public LoggerDecorator(Logger logger) {
        this.decoratedLogger = logger;
    }

    @Override
    public void log(String message) {
        decoratedLogger.log(message);
    }
}
具体装饰器

现在,我们可以创建具体的装饰器来添加不同的功能。

// 日志级别装饰器
public class LogLevelDecorator extends LoggerDecorator {
    private final LogLevel level;

    public LogLevelDecorator(Logger logger, LogLevel level) {
        super(logger);
        this.level = level;
    }

    @Override
    public void log(String message) {
        if (message.startsWith(level.getPrefix())) {
            decoratedLogger.log(message);
        }
    }

    public enum LogLevel {
        INFO("INFO"), DEBUG("DEBUG"), ERROR("ERROR");

        private final String prefix;

        LogLevel(String prefix) {
            this.prefix = prefix;
        }

        public String getPrefix() {
            return prefix;
        }
    }
}

// 日志格式化装饰器
public class LogFormatterDecorator extends LoggerDecorator {
    public LogFormatterDecorator(Logger logger) {
        super(logger);
    }

    @Override
    public void log(String message) {
        String formattedMessage = String.format("%s - %s", new Date(), message);
        decoratedLogger.log(formattedMessage);
    }
}

// 日志持久化装饰器
public class LogPersistenceDecorator extends LoggerDecorator {
    private final String filePath;

    public LogPersistenceDecorator(Logger logger, String filePath) {
        super(logger);
        this.filePath = filePath;
    }

    @Override
    public void log(String message) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, true))) {
            writer.write(message + System.lineSeparator());
        } catch (IOException e) {
            e.printStackTrace();
        }
        decoratedLogger.log(message);
    }
}
使用装饰器
public class LoggingSystem {
    public static void main(String[] args) {
        Logger logger = new ConsoleLogger();
        logger = new LogFormatterDecorator(logger);
        logger = new LogPersistenceDecorator(logger, "logs.txt");
        logger = new LogLevelDecorator(logger, LogLevel.INFO);

        logger.log("INFO: This is an informational message.");
        logger.log("DEBUG: This is a debug message.");
        logger.log("ERROR: This is an error message.");
    }
}

在这个示例中,我们构建了一个灵活的日志记录系统,它允许在运行时动态地添加日志级别过滤、格式化和持久化。这种灵活性是通过装饰器模式实现的,它允许我们根据需要组合不同的日志记录功能,而无需修改现有的日志记录代码。

优缺点:

优点

  • 灵活性:可以灵活地为对象添加功能;
  • 扩展性:易于扩展新功能;
  • 透明性:装饰器和组件具有一致的接口。

缺点

  • 复杂性:过度使用装饰器模式可能会使系统复杂化。
  • 性能影响:每次装饰都可能影响性能。

装饰器模式VS代理模式

在代理模式中,代理类附加的是跟原始类无关的功能;
装饰器模式中,装饰器类附加的是跟原始类相关的增强功能。

// 代理模式的代码结构
public interface IA {
  void f();
}
public class A impelements IA {
  public void f() { //... }
}
public class AProxy implements IA {
  private IA a;
  public AProxy(IA a) {
    this.a = a;
  }
  
  public void f() {
    // 新添加的代理逻辑
    a.f();
    // 新添加的代理逻辑
  }
}
// 装饰器模式的代码结构
public interface IA {
  void f();
}
public class A implements IA {
  public void f() { //... }
}
public class ADecorator implements IA {
  private IA a;
  public ADecorator(IA a) {
    this.a = a;
  }
  
  public void f() {
    // 功能增强代码
    a.f();
    // 功能增强代码
  }
}

结论

装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能。这也是判断是否该用装饰器模式的一个重要的依据。

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值