【问题标题】:Best Pattern for Storing Common Settings across Multiple Classes跨多个类存储通用设置的最佳模式
【发布时间】:2012-09-25 15:54:39
【问题描述】:

我正在创建两个单独的类来访问自定义文件。让我们将我的课程称为MyReaderMyWriter

我遵循与StreamReaderStreamWriter 等.NET 类相同的模式,其中有一个单独的类用于读取和写入。除了遵循既定模式之外,这也为我解决了一些其他问题。

但是,我确实需要为 reader 和 writer 类设置一些通用设置。例如,我有一个用户应该能够更改的分隔符。我还有一些固定数据,其中包含用于解析的常用信息。

有人可以提出一个好的模式,尤其是遵循常见的 .NET 框架实践的模式,为这样的多个类创建通用设置吗?我的类已经继承自 .NET 类。似乎多重继承可能是一种方式,但在 C# 中似乎不受支持。

(我使用的是 Visual Studio 2012。)

【问题讨论】:

    标签: c# inheritance multiple-inheritance


    【解决方案1】:
    public interface IStreamFilter
    {
       string Delimiter {get; private set;}
       List<string> FilterCriteria {get; private set;}
    }
    
    public class StreamFilter : IStreamFilter
    {
       public string Delimiter {get;}
       public List<string> FilterCriteria {get;}
    
       public void StreamFilter (string delimiter, List<string> filterCriteria)
       {
           this.Delimiter = delimiter;
           this.FilterCriteria = filterCriteria;
       }
    }
    

    您可以在 Reader 和 Writer 类的构造函数中传递 IStreamFilter 的实例。

     public class MyReader
     {
          private IStreamFilter _streamFilter;
    
          public MyReader(IStreamFilter streamFilter)
          {
               this._streamFilter = streamFilter;
          }
    
          public string ReadString()
          { 
              var readString = reader.GetString(x => x.Contains(this._streamFilter.Delimiter);
               // apply the filter for reading string
          }
     }   
    

    在您想要实例化 MyReader 类的代码中的任何位置,您都可以在构造函数中创建一个新的 IStreamFilter 实例,并根据用户偏好(假设来自用户配置文件)设置分隔符和其他过滤条件。然后将该 StreamFilter 实例传递给 MyReader 实例。这样,您可以即时自定义过滤器设置,而无需依赖单例。

    【讨论】:

      【解决方案2】:

      这似乎是Singleton 可能有意义的少数情况之一:

      public abstract class MyBase
      {
          // This is the .NET class you're inheriting from, just putting it as a placeholder.
      }
      
      public class MyReader : MyBase
      {
          private static readonly IMySettings settings = MySettings.Instance;
      }
      
      public class MyWriter : MyBase
      {
          private static readonly IMySettings settings = MySettings.Instance;
      }
      
      internal interface IMySettings
      {
          // Define your setting's properties, such as delimiter character.
      }
      
      internal sealed class MySettings : IMySettings
      {
          private MySettings()
          {
          }
      
          public static IMySettings Instance
          {
              get
              {
                  return Nested.Instance;
              }
          }
      
          // Implement your setting's properties, such as delimiter character.
      
          private static class Nested
          {
              private static readonly IMySettings instance = new MySettings();
      
              // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
              static Nested()
              {
              }
      
              public static IMySettings Instance
              {
                  get
                  {
                      return instance;
                  }
              }
          }
      }
      

      希望这会有所帮助。

      【讨论】:

      • 谢谢。直到现在我都没有机会仔细讨论这个问题。但老实说,我不明白为什么需要大部分代码。既然MyReaderMyWriter 的所有实例都引用了MySettings 的同一个实例,为什么不直接将MySettings 设为静态并直接引用它呢?为什么要使用所有接口、继承和私有类?
      • 单元可测试性,松耦合,如果你需要它仍然有对象继承。那是几个。我可能宁愿去什么 tranceporter 并通过构造函数注入它们,但这不是 .NET FCL 所做的,我试图通过一些额外的最佳实践来模拟它。
      【解决方案3】:

      尝试使用接口。 interfaceabstract class 类似,但只能包含由实现它们的类“充实”的方法或属性定义。然后类可以根据需要实现任意数量的接口。看看IEnumerable 如何允许列表、字典和数组共享一组公共方法,允许它们在foreach 中使用,或者IDisposable 如何允许在using 中声明一个类。

      我制作了一组墨迹文本框控件,它们都应该从多个应用程序的用户配置中获取其显示样式设置,因此我让它们从 IinkInputSettings 接口中获取这些设置并在所有应用程序中实现该接口UserConfig 类。

      或者,您可以通过 Singleton 实现全局配置:

      public class GlobalConfig{
          /* your configuration properties here */
          private static GlobalConfig instance = null;
          public static GlobalConfig Instance{
              get{
                  if(instance == null) instance=new GlobalConfig();
                  return instance;
              }
          }
          private GlobalConfig(){ /* set default property values */ }
      }
      

      这比具有静态成员的静态类要好,因为它仅在您第一次使用时才被实例化。

      【讨论】:

      • 谢谢,但我不确定这会有什么帮助。它将定义接口,但我仍然必须在两个不同的地方实现该接口。我的理想场景是用户可以在一个地方设置分隔符,例如,它会影响阅读器和编写器类。
      • 您希望它影响两个类的每个实例吗?你可以用单例做到这一点。
      • 我不确定。您能否详细说明如何使用我描述的两个类来实现?
      【解决方案4】:

      您可以使用基于构造函数的依赖注入将设置类插入到类中。让 IoC 容器启动设置类(无论是否为单例)并基于基类或接口注入它会很简单。

      【讨论】:

        猜你喜欢
        • 2016-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-26
        • 2011-04-11
        • 1970-01-01
        • 2013-03-28
        相关资源
        最近更新 更多