简单的喷油器装饰,具有额外的依赖性

本文关键字:依赖性 简单 | 更新日期: 2023-09-27 17:57:07

>我有一个装饰器SomethingLoggerDecorator,应该用日志记录来装饰ISomething实例:

public class SomethingLoggerDecorator : ISomething
{
    private readonly ISomething decoratee;
    private readonly ILogger logger;
    public SomethingLoggerDecorator(ISomething decoratee, ILogger logger)
    {
        this.decoratee = decoratee;
        this.logger = logger;
    }
    public void DoSomething()
    {
        this.logger.Info("Doing Something");
        this.decoratee.DoSomething();
    }
    public void DoSomethingElse(string withThis)
    {
        this.logger.Info("Doing Something Else with " + withThis);
        this.decoratee.DoSomethingElse(withThis);
    }
}

如何使用简单注入器用SomethingLoggerDecorator装饰ISomething实例,并使用静态工厂方法将ILogger实例注入到每个装饰器中LogManager.GetLogger(decoratee.GetType())其中装饰者是要修饰的实际实例?此外,注塑ILoggerSomethingLoggerDecorator的使用寿命应始终与装饰者的使用寿命相匹配。

简单的喷油器装饰,具有额外的依赖性

在Simple Injector中有多种方法可以做到这一点。

首先,你可以让装饰器的构造函数依赖于DecoratorContext类。DecoratorContext包含有关修饰器的上下文信息。它包含诸如包装装饰器的类型和修饰的实际实现的类型(实际实例)等信息。因此,您的装饰器可能如下所示:

public class SomethingLoggerDecorator : ISomething
{
    private readonly ISomething decoratee;
    private readonly DecoratorContext context;
    public SomethingLoggerDecorator(ISomething decoratee, DecoratorContext context)
    {
        this.decoratee = decoratee;
        this.context = context;
    }
    public void DoSomething()
    {
        var logger = LogManager.GetLogger(this.context.ImplementationType);
        logger.Info("Doing Something");
        this.decoratee.DoSomething();
    }
}

使用此DecoratorContext类的缺点是,您的装饰器需要依赖于简单注入器,这基本上意味着您必须将装饰器移动到组合根中,以防止您的应用程序依赖于 DI 库。您可以在此处找到有关使用此DecoratorContext类的更多信息。

另一种选择是使您的装饰器通用,并为可以制造正确装饰器的RegisterDecorator重载之一提供装饰器类型工厂。例如:

public class SomethingLoggerDecorator<TImplementation> : ISomething
{
    private readonly ISomething decoratee;
    public SomethingLoggerDecorator(ISomething decoratee)
    {
        this.decoratee = decoratee;
    }
    public void DoSomething()
    {
        var logger = LogManager.GetLogger(typeof(TImplementation));
        logger.Info("Doing Something");
        this.decoratee.DoSomething();
    }
}

或者可选:

public class SomethingLoggerDecorator<TImplementation> : ISomething
{
    private readonly ISomething decoratee;
    private readonly ILogger<TImplementation> logger;
    public SomethingLoggerDecorator(ISomething decoratee, ILogger<TImplementation> logger)
    {
        this.decoratee = decoratee;
        this.logger = logger;
    }
    public void DoSomething()
    {
        this.logger.Info("Doing Something");
        this.decoratee.DoSomething();
    }
}

使用这两种实现,您可以按如下方式注册装饰器:

container.RegisterDecorator(typeof(ISomething),
    c => typeof(SomethingLoggerDecorator<>).MakeGenericType(c.ImplementationType),
    Lifestyle.Transient,
    predicate: c => true);

使用第二个实现,您将问题稍微移动到泛型ILogger<T>抽象,但实现可能如下所示:

public class Log4netAdapter<T> : ILogger<T>
{
    public void Log(LogEntry entry) {
        var logger = LogManager.GetLogger(typeof(T));
        // TODO: log
    }
}