问题描述
弄清楚我是否以正确的方式使用装饰器模式时遇到问题.假设我正在开发控制台应用程序.在此应用程序中,我定义了一个简单的IConfigPathProvider接口,该接口将提供某个类的配置文件路径.
I'm having a problem figuring out if I'm using the decorator pattern the right way. Let's suppose I'm working on a console application. In this application I have defined a simple IConfigPathProvider interface, which will provide a configuration file path to some class.
public interface IConfigPathProvider
{
string GetConfigPath();
}
该路径存储在控制台应用程序的app.config文件的appSettings部分中.
The path is stored in the appSettings section of the console application's app.config file.
public class AppSettingsConfigPathProvider : IConfigPathProvider
{
public string GetConfigPath()
{
return System.Configuration.ConfigurationManager.AppSettings["configPath"];
}
}
问题是这个路径也被加密了,所以...
The thing is this path is also encrypted, so...
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);
}
}
但是,等等:还没有结束.我必须在路径上添加特定部分才能正确处理.
But, wait: it's not over. I have to add a specific portion to the path to get it right.
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));
}
}
现在-为什么不呢? -让我们添加一些日志记录.
And now - why not? - let's add some logging.
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.
Of course the instant outcome is the separation of concerns, BUT what about the added complexity in instantiating the object? You need to know which decorator comes first and in which order they should be chained, otherwise you'll end up with a buggy IConfigPathProvider.
new LoggingConfigPathProvider(
new AppendSectionConfigPathProvider(
new DecryptingConfigPathProvider(
new AppSettingsConfigPathProvider(),
decrypter));
这只是一个简单的提供程序.在一个相当复杂的应用程序中,您可能会遇到具有多个引用的多个组件...这很容易导致维护的噩梦.现在,这是否是众所周知的缺点,或者我只是以错误的方式使用了这种模式?
And this is just a simple provider. In a rather complex application you'd likely come across multiple components with multiple references...this could easily led to a maintenance nightmare. Now, is this a well-known drawback or I'm just using this pattern in the wrong way?
推荐答案
您不一定正确.与其立即装饰对象,不如保持某种可验证的惰性的装饰shema ,可以通过调用.Build()
将该对象转换为所需的(最终的,随时可用的)对象. >.只是一个代码草图:obj.DecorateWith<Decorator1>().DecorateWith<Decorator2>().DecorateWith(() => new Decorator3(IContainer.Resolve<SomeWhatArgument> ...).Build()
.它无疑使事情变得更加困难,但是,只要装饰是正确的方法,并且您的项目确实足够大,可以从如此高的抽象度中受益,它就能解决您的问题.
You're not necessarily correct. Rather than decorating object right away, keep some kind of a decoration shema, validatable, lazy, which can be converted into needed (final, ready-to-use) object by calling, let say, .Build()
. Just a code sketch: obj.DecorateWith<Decorator1>().DecorateWith<Decorator2>().DecorateWith(() => new Decorator3(IContainer.Resolve<SomeWhatArgument> ...).Build()
. It makes things definitely harder, however as long as decorating is right way to go and your project is indeed big enough to benefit from such a high abstraction, it will solve your problem.
这篇关于装饰图案混乱的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!