【问题标题】:Decorator pattern with decorators that can be implemented independently带有可以独立实现的装饰器的装饰器模式
【发布时间】:2017-12-15 11:39:33
【问题描述】:

我正在编写一系列记录器。一个将写入控制台,一个写入标准输出,一个写入专有文件格式。在任何时候,我都希望这些记录器中的任何一个都能够独立实施和工作。

我原本打算使用装饰器模式将记录器堆叠在一起,但我意识到装饰器并不打算单独承担额外的责任。

所以我的问题: 1) 能够独立生活的责任是否可以接受? 2)装饰器模式仍然是正确的道路,还是有更适合我描述的问题的模式?

【问题讨论】:

  • decorators are not intended to have the additional responsibilities stand on their own 到底是什么意思?装饰器应该始终松散耦合,否则您将失去将它们应用于代码不同区域的好处。
  • 在我阅读的示例中,描述了装饰器本质上是附加职责的,并不打算独立存在。我很高兴知道我的假设是不正确的。

标签: design-patterns decorator


【解决方案1】:

我使用过伪 C# - 如果您更喜欢其他语言,请告诉我。

要实现这一点,您首先要创建一个日志接口。任何进行日志记录的对象都将遵守这一点:

public interface Logger
{
  void Log(string message);
}

接下来你需要你的装饰器类来包装你的日志功能。如果您不希望人们直接实例化它,这也可能是抽象的。它接受一个记录器对象并将所有日志消息代理到:

public class LoggerDecorator : Logger 
{
  Logger logger;

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

  public override void Log(string message) 
  {
    logger.log(message);
  }
}

可以创建独立的记录器:

public class StdoutLogger : Logger 
{
  public override void Log(string message) 
  {
    // Log message to stdout
  }
}

或“堆叠”记录器,只需使用您的 decorator 包装这些记录器:

public class FileAndStdoutLogger : LoggerDecorator 
{
    public FileAndStdoutLogger(Logger logger) 
    {
      super(logger);
    }

    public void log(String message) 
    {
      logger.log(msg);

      // Log to file
    }
}

然后您可以创建独立或修饰的记录器:

var stdoutLogger = new StdoutLogger();
stdoutLogger.log("This will log only to stdout");

// Will output "This will log only to stdout" to stdout

var fileAndStdoutLogger = new FileAndStdoutLogger(new StdoutLogger());
fileAndStdoutLogger.log("This will log to file & stdout");

// Will output "This will log to file & stdout" to file and stdout

如果您需要更多示例,请告诉我。

【讨论】:

  • 我在 C++ 中,但这是我一直在走的路。任何一个伐木工都可以独立生活。如果我没有堆叠记录器,那么修饰的记录器包含一个我可以评估的 nullptr,或者一个什么都不做的空记录器。
  • 那么我会说你走在正确的道路上。但是为什么你认为装饰的记录器会包含一个空引用?
  • 因为我不一定想要一个“基础”记录器。由于任何记录器都可以按任何顺序添加,因此它们都必须能够注入另一个记录器实例。
  • 您将为每种类型的记录器实现一个LoggerDecorator。您是否正在考虑只有一个记录器的情况?在这种情况下是的,您需要在基类/超类中调用 log 之前进行检查
  • 确实如此。谢谢!
【解决方案2】:

我原本打算使用装饰器模式将记录器堆叠在顶部 彼此的

我认为这不是一个好主意。装饰器模式应该以某种method call intercepcion 或AOP 的形式工作。

这意味着在执行函数体之前和/或之后执行一些代码。正在筑巢。我不会嵌套我的记录器;我不想让一个记录器依赖于其他记录器。

一个好的策略是创建一个通用记录器并向其添加侦听器。每个侦听器都有自己的策略来写入记录的数据。就像 .NET 环境中的 Trace and Debug 一样。然后,您的通用记录器只需遍历添加的侦听器列表并在每个上调用 log(message)。

然后应用装饰器模式来组合装饰服务,以解决诸如日志记录和安全性等横切关注点。

 Public Interface IMyService{
    int someAction();
}

Public Class MyService:IMyService{
    int someAction(){//impl goes here}
}

Public Class SecureMyService:IMyService{
    SecureMyService(IMyService innerService){
      inner = innerService;
    }
    int someAction(){
       if (!HasRights()) {throw authorizationException};
       return inner.someAction();
    }
}

Public Class LoggedMyService:IMyService{
    SecureMyService(IMyService innerService){
      inner = innerService;
    }
    int someAction(){
       logger.log("invoking some Action");
       return inner.someAction();
    }
}

//resolve decorated service. A DI container does wonderful things for decorator pattern ;)
IMyService GetService(){
    myService = new MyService();
    mySecuredService = new SecureMyService(myService);
    myLoggedAndSecuredService = new LoggedMyService(mySecuredService);
    return myLoggedAndSecuredService;
}

【讨论】:

    猜你喜欢
    • 2012-02-16
    • 2018-03-10
    • 2011-08-19
    • 2015-06-02
    • 2012-01-28
    • 1970-01-01
    • 1970-01-01
    • 2020-02-29
    • 1970-01-01
    相关资源
    最近更新 更多