0

我正在创建一个平台/基础组件(.NET 程序集集),它将负责访问(读/写)配置值。该组件将由将在平台上创建的其他组件使用。

我希望这个组件对消费者来说易于使用,同时具有很高的可测试性和可维护性。在我当前的设计中,我有一个包含一些方法(例如 GetKeyValueSetting)的静态类(ConfigurationManager)。此 ConfigurationManager 类的特殊之处在于它既可以从本地 .NET .config 文件中获取配置值,也可以从 SharePoint 列表(一些组件托管在共享 SharePoint 环境中)甚至从另一个共享配置值存储中获取配置值. Manager 应该能够以优先方式从多个位置读取:

  • 如果在 SharePoint 上运行:1. SharePointSettingsProvider,2. SharedStoreSettingsProvider
  • 如果不在 SharePoint 上运行: 1. ConfigFileSettingsProvider 2. SharedStoreSettingsProvider

我知道静态类会在可测试性、可扩展性等方面产生很多问题,所以我不想使用它。我的下一个替代方案是 Singleton,但就上述 -ilities 而言,这并不是一个更好的解决方案。有更好的解决方案的想法吗?

我目前的设计如下:

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();
}
4

1 回答 1

1

为什么不这样:

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 是抽象的,所以调用代码可以很容易地 Mock
  • 很容易得到一个默认的实现
  • 调用程序集可以很容易地用不同的提供者和工厂来配置它
  • 调用程序集不能耦合到具体类型
  • 您可以轻松更改特定的实现类型(即,也许您需要一个缓存代理,这样您就不需要经常对共享点进行昂贵的调用)
  • 您保持所有易于测试的能力
  • 您可以重构为单例或生命周期管理的其他变体,而无需更改客户端代码

如果调用者真的讨厌这个,并且不介意他们的单元测试有时调用共享点站点,你可以添加一个这样的方便方法:

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());
}
于 2013-01-26T16:42:37.200 回答