Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 装饰图案混乱_C#_Oop_Design Patterns_Decorator - Fatal编程技术网

C# 装饰图案混乱

C# 装饰图案混乱,c#,oop,design-patterns,decorator,C#,Oop,Design Patterns,Decorator,我很难弄清楚我是否正确使用了装饰图案。假设我正在开发一个控制台应用程序。在这个应用程序中,我定义了一个简单的IConfigPathProvider接口,它将提供某个类的配置文件路径 public interface IConfigPathProvider { string GetConfigPath(); } 该路径存储在控制台应用程序的app.config文件的appSettings部分 public class AppSettingsConfigPathProvider : ICo

我很难弄清楚我是否正确使用了装饰图案。假设我正在开发一个控制台应用程序。在这个应用程序中,我定义了一个简单的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;
    }
}
分而治之

当然,即时结果是分离关注点,但是实例化对象时增加的复杂性又如何呢您需要知道哪一个decorator首先出现,以及它们应该以何种顺序链接,否则您最终会遇到一个有缺陷的IConfigPathProvider

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

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

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

很多小东西。使用Decorator的设计通常会生成系统 由许多看起来很像的小物体组成。对象只是不同而已 在他们相互联系的方式上,而不是在他们的阶级或价值观上 他们的变量。虽然这些系统很容易被那些 理解它们,它们可能很难学习和调试


你不一定是对的。不要马上装饰对象,而是保留某种装饰shema、可验证、惰性,可以通过调用
.Build()
将其转换为所需的(最终的、随时可用的)对象。只是一个代码草图:
obj.DecorateWith().DecorateWith().DecorateWith(()=>newdecorator3(IContainer.Resolve…).Build()
。这无疑会让事情变得更加困难,但只要装饰是正确的方式,并且您的项目确实足够大,能够从如此高的抽象中获益,它就会解决您的问题。

我们的代码也有类似的情况,但我们并不太重视它。就我而言,用错误的ord连接装饰程序ER是一个程序员错误。此外,作为程序员,你需要指定正确的顺序,因为你正在执行一个定义良好的操作序列。你可以把构造器模式看作一个替代品,在这样的情况下,IMHO在代码的可读性上更好地工作。Dynamic,即代码的不同部分可以添加不同的提供程序以获得最终对象,在这种情况下,decorator更好。但看起来您正在使用该模式立即创建/构建对象。在这种情况下,构建器模式应该更适合。@AD.Net实际上,我不认为构建器模式最适合这种情况s:1)唯一的可选/动态参数是日志记录,因此无论发生什么情况,都必须链接每个其他装饰器。请记住,这只是一个相当简单的例子,在生产系统中,我甚至可能有10多个强制装饰器(大而混乱的构造函数);2) 如果我决定使用构建器方法来提高创建对象的可读性,而不是加重构建器构造函数的负担,那么我最终会增加歧义(我应该先调用哪个方法?以后调用哪个方法?按什么顺序?)