具有可独立实现的装饰器的装饰器模式

时间:2017-12-15 11:39:33

标签: design-patterns decorator

我正在写一系列记录器。一个将写入控制台,一个写入stdout,一个写入专有文件格式。在任何时候,我都希望能够实现这些记录器并自行工作。

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

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

2 个答案:

答案 0 :(得分: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

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

答案 1 :(得分:1)

  

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

我不认为这是个好主意。装饰者模式应该作为某种method call intercepcionAOP

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

一个好的策略是创建一个通用记录器并为其添加侦听器。每个监听器都有自己的策略来编写loged数据。就像.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;
}