装饰图案混乱

时间:2018-09-24 10:21:46

标签: c# oop design-patterns decorator

弄清楚我是否以正确的方式使用装饰器模式时遇到问题。假设我正在开发控制台应用程序。在此应用程序中,我定义了一个简单的IConfigPathProvider接口,该接口将提供某个类的配置文件路径。

public interface IConfigPathProvider
{
    string GetConfigPath();
}

该路径存储在控制台应用程序的app.config文件的appSettings部分中。

public class AppSettingsConfigPathProvider : IConfigPathProvider
{
    public string GetConfigPath()
    {
        return System.Configuration.ConfigurationManager.AppSettings["configPath"];
    }
}

问题是此路径也已加密,所以...

public class DecryptingConfigPathProvider : IConfigPathProvider
{
    private readonly IConfigPathProvider _provider;
    private readonly IStringDecrypter _decrypter;

    public DecryptingConfigPathProvider(IConfigPathProvider provider, 
        IStringDecrypter decrypter)
    {
        _provider = provider ?? throw new ArgumentNullException(nameof(provider));
        _decrypter = decrypter ?? throw new ArgumentNullException(nameof(decrypter));
    }

    public string GetConfigPath()
    {
        var path = _provider.GetConfigPath();
        //decrypting method of IStringDecrypter interface
        return _decrypter.DecryptString(path);
    }
}

但是,等等:还没有结束。我必须在路径上添加特定部分才能正确处理。

public class AppendSectionConfigPathProvider : IConfigPathProvider
{
    private readonly IConfigPathProvider _provider;

    public AppendSectionConfigPathProvider(IConfigPathProvider provider)
    {
        _provider = provider ?? throw new ArgumentNullException(nameof(provider));
    }

    public string GetConfigPath()
    {
        var path = _provider.GetConfigPath();

        return System.IO.Path.Combine(
            System.IO.Path.GetDirectoryName(path),
            "section", 
            System.IO.Path.GetFileName(path));
    }
}

现在-为什么不呢? -让我们添加一些日志记录。

public class LoggingConfigPathProvider : IConfigPathProvider
{
    private readonly static ILog _log = 
        LogManager.GetLogger(typeof(LoggingConfigPathProvider));

    private readonly IConfigPathProvider _provider;

    public LoggingConfigPathProvider(IConfigPathProvider provider)
    {
        _provider = provider ?? throw new ArgumentNullException(nameof(provider));
    }

    public string GetConfigPath()
    {
        _log.Info("Getting config path...");
        var path = _provider.GetConfigPath();

        _log.Info("Config path retrieved successfully!");
        return path;
    }
}
  

划分和影响

当然,即时结果是关注点分离, BUT 那么实例化对象所增加的复杂性又如何呢? 您需要知道哪个装饰器首先出现,以及应该按什么顺序链接,否则,您将遇到一个有问题的IConfigPathProvider。

new LoggingConfigPathProvider(
    new AppendSectionConfigPathProvider(
        new DecryptingConfigPathProvider(
            new AppSettingsConfigPathProvider(), 
            decrypter));

这只是一个简单的提供程序。在一个相当复杂的应用程序中,您可能会遇到具有多个引用的多个组件...这很容易导致维护噩梦。现在,这是一个众所周知的缺点,还是我只是以错误的方式使用了这种模式?

2 个答案:

答案 0 :(得分:1)

这是一个众所周知的缺点。 GoF提到了装饰者模式的以下责任。

  

很多小物件。使用Decorator的设计通常会导致系统   由许多看起来相似的小物体组成。对象仅不同   它们相互联系的方式,而不是他们的阶级或价值   他们的变量。尽管这些系统很容易被那些   了解它们,可能很难学习和调试。

答案 1 :(得分:0)

您不一定正确。与其立即装饰对象,不如保持某种可验证的惰性的装饰shema ,可以通过调用{例如{},将其转换为所需的(最终的,立即可用的)对象。 1}}。只是一个代码草图:.Build()。它无疑使事情变得更加困难,但是,只要装饰是正确的方法,并且您的项目确实足够大,可以从如此高的抽象度中受益,它将解决您的问题。