C# 具有构造函数参数的通用可访问类/对象
我正在创建一个平台/基础组件(一组.NET程序集),它将负责访问(读取/写入)配置值。此组件将由将在平台上创建的其他组件使用 我希望这个组件易于用户使用,但也具有很高的可测试性和可维护性。在我当前的设计中,我有一个静态类(ConfigurationManager),它包含一些方法(例如GetKeyValueSetting)。此ConfigurationManager类的特殊之处在于,它既可以从本地.NET.config文件中获取配置值,也可以从SharePoint列表(某些组件托管在共享SharePoint环境中)甚至从另一个共享配置值存储中获取配置值。经理应能够以优先方式从多个位置读取:C# 具有构造函数参数的通用可访问类/对象,c#,unit-testing,design-patterns,architecture,dependency-injection,C#,Unit Testing,Design Patterns,Architecture,Dependency Injection,我正在创建一个平台/基础组件(一组.NET程序集),它将负责访问(读取/写入)配置值。此组件将由将在平台上创建的其他组件使用 我希望这个组件易于用户使用,但也具有很高的可测试性和可维护性。在我当前的设计中,我有一个静态类(ConfigurationManager),它包含一些方法(例如GetKeyValueSetting)。此ConfigurationManager类的特殊之处在于,它既可以从本地.NET.config文件中获取配置值,也可以从SharePoint列表(某些组件托管在共享Shar
- 如果在SharePoint上运行:1。SharePointSettingsProvider,2。共享存储设置提供程序
- 如果未在SharePoint上运行:1。配置文件设置提供程序2。共享存储设置提供程序
public static class ConfigurationManager
{
// internal for testability
internal IEnumerable<ISettingsProvider> SettingsProviders {get;set;}
// internal for testability
internal ISettingsProviderFactory ProvidersFactory {get;set;}
public static string GetKeyValueSetting(string key)
{
}
}
public interface ISettingsProvider
{
string GetKeyValueSetting(string key);
}
public class ConfigFileSettingsProvider : ISettingsProvider
{
}
public class SharePointSettingsProvider : ISettingsProvider
{
}
public class SharedStoreSettingsProvider : ISettingsProvider
{
}
public interface ISettingsProviderFactory
{
IEnumerable<ISettingsProvider> GetProviders();
}
公共静态类配置管理器
{
//内部可测试性
内部IEnumerable设置提供程序{get;set;}
//内部可测试性
内部ISettingsProviderFactory提供程序工厂{get;set;}
公共静态字符串GetKeyValueSetting(字符串键)
{
}
}
公共接口设置提供程序
{
字符串GetKeyValueSetting(字符串键);
}
公共类ConfigFileSettingsProvider:ISettingsProvider
{
}
公共类SharePointSettingsProvider:ISettingsProvider
{
}
公共类SharedStoreSettingsProvider:ISettingsProvider
{
}
公共接口正在设置ProviderFactory
{
IEnumerable GetProviders();
}
为什么不这样做:
public abstract class ConfigurationManager
{
public abstract string GetKeyValueSetting(string key);
public static ConfigurationManager GetInstance()
{
return GetInstance(GetDefaultSettingProvider(), GetDefaultProviderFactory());
}
public static ConfigurationManager GetInstance(ISettingsProvider provider, IProviderFactory factory)
{
return new InternallyVisibleConfigurationManagerImplementation(provider, factory);
}
}
这有很多好处:
- ConfigurationManager是抽象的,因此调用代码可以很容易地模拟它
- 很容易获得默认实现
- 调用程序集可以轻松地使用不同的提供程序和工厂对其进行配置
- 调用程序集不能耦合到具体类型
- 您可以轻松更改特定的实现类型(例如,您可能需要一个缓存代理,这样您就不需要经常对sharepoint进行昂贵的调用)
- 您保留了所有简单的可测试性
- 您可以重构为单例或生命周期管理的其他变体,而无需更改客户端代码
public static string GetKeyValueSetting(string key)
{
return GetInstance().GetKeyValueSetting(key);
}
internal class OrderedCompositeSettingProvider : ISettingProvider
{
private readonly ISettingProvider[] _providers;
private OrderedCompositeSettingProvider(ISettingProvider[] providers)
{
_providers = providers;
}
internal static ISettingProvider GetInstance(params ISettingProvider[] providers)
{
return new OrderedCompositeSettingProvider(providers)
}
public string GetKeyValueSetting(string key)
{
foreach(var provider in _providers)
{
var setting = provider.GetKeyValueSetting(key);
if(!string.IsNullOrEmpty(setting)) return setting;
}
return string.empty;
}
}
编辑
要使用多个存储,请创建如下类:
public static string GetKeyValueSetting(string key)
{
return GetInstance().GetKeyValueSetting(key);
}
internal class OrderedCompositeSettingProvider : ISettingProvider
{
private readonly ISettingProvider[] _providers;
private OrderedCompositeSettingProvider(ISettingProvider[] providers)
{
_providers = providers;
}
internal static ISettingProvider GetInstance(params ISettingProvider[] providers)
{
return new OrderedCompositeSettingProvider(providers)
}
public string GetKeyValueSetting(string key)
{
foreach(var provider in _providers)
{
var setting = provider.GetKeyValueSetting(key);
if(!string.IsNullOrEmpty(setting)) return setting;
}
return string.empty;
}
}
然后在ConfigurationManager工厂方法中:
public static ConfigurationManager GetInstance()
{
return GetInstance(GetAppropriateProvider(), GetDefaultProviderFactory());
}
private static ISettingsProvider GetAppropriateProvider()
{
if(ShouldUseSharepoint())
return OrderedCompositeSettingProvider.GetInstance(new SharepointProvider(), new StoredSettingsProvider());
return OrderedCompositeSettingProvider.GetInstance(new ConfigFileProvider(), new StoredSettingsProvider());
}
出于某种原因,您想要/需要全局状态吗?它会以多线程方式访问吗?也许我应该更新我的问题。我不需要全球国家。我只希望我的消费者能够使用我的ConfigurationManager类,而无需为他们要检索的每个键值提供ISettingsProvider实例。Thx获取答案Tallseth。我更新了问题,并添加了一些信息,说明经理需要为特定环境决定以何种顺序使用哪种设置Provider。您能详细说明一下您将如何实施该要求吗?更新。根据上下文的更多细节,您可能希望将GetAppPriateProvider中的逻辑封装到ProviderFactory中。我之所以没有这样做,是因为我不完全理解您希望如何使用该类,也因为它让我有了更多的自由。