6

我正在尝试实现一个首选项系统,程序员可以在其中指定首选项名称、类型(布尔值、整数、字符串等)以及可选的默认值。我一直在思考并且无法想出的是用于存储到磁盘/从磁盘加载的通用解决方案。我希望设计足够通用以处理多种格式(即文本文件、Windows 注册表或 Apple 的属性列表)。简单的解决方案是为每种存储格式制作转换器,并在已经选择存储格式时沿线的某个地方制作转换器,遍历首选项并在其类型上切换大小写。

我被告知在一个类型上做一个 switch-case 不是一个好的解决方案,我理解为什么:如果我添加一个类型,我需要去修改所有这些 switch-case 块。那么我应该怎么做呢?通常的答案是让正在检查其类型的对象实现一个公共接口并知道如何自己执行操作。

但这对我来说似乎很荒谬,让偏好值知道如何将自己存储在文本文件、Windows 注册表和 Apple 属性列表中。这只是解决了问题。如果我添加一个新的变压器,我需要去修改所有类型,而不是添加一个需要我去修改转换器的新类型!

我想这是一个常见的设计问题,但我找不到任何好的解决方案。

4

1 回答 1

3

访问者模式的经典使用。尽管您有时会看到更通用的模式表达,但这里有一些通过访问者模式的持久层的伪代码。

注意,首选项不需要知道如何保存自己,只需将自己传递给存储机制即可:

abstract BasePreference
{
    abstract Persist(PreferenceStorage ps);
}


NumericPreference : BasePreference
{
   string Name;
   int Value;
   int Default

   Persist(PreferenceStorage ps)
   {
      ps.Save(this);
   }

}


StringPreference : BasePreference
{
   string Name;
   string Value;
   string Default

   Persist(PreferenceStorage ps)
   {
      ps.Save(this);
   }   
}


DateRangePreference : BasePreference
{
   string Name;
   DateTime StartOfRange;
   DateTime EndOfRange;
   DateTime DefaultStartOfRange;
   DateTime DefaultEndOfRange;

   Persist(PreferenceStorage ps)
   {
      ps.Save(this);
   }   
}

接下来,PreferenceStorage 利用方法重载来允许为每个 pref 子类型运行单独的代码。类型上没有开关块:

abstract PreferenceStorage 
{
   abstract void Save(NumericPreference pref);
   abstract void Save(StringPreference pref);
   abstract void Save(DateRangePreference pref);   
}

最后,PreferenceStorage 的子类负责处理机制或保存数据:

XmlPreferenceStorage : PreferenceStorage
{
   void Save(NumericPreference pref)
   {
      // save number to xml 
   }

   void Save(StringPreference pref)
   {
      // save string to xml 
   }   

   void Save(DateRangePreference pref)
   {
      // save date range to xml 
   }      
}



RegistryPreferenceStorage : PreferenceStorage
{
   void Save(NumericPreference pref)
   {
      // save number to registry 
   }

   void Save(StringPreference pref)
   {
      // save string to registry 
   }   

   void Save(DateRangePreference pref)
   {
      // save date range to registry 
   }      
}

(Uggg,为什么这种格式如此糟糕?抱歉缩进不好,通常在 SO 上很好的代码格式)

于 2012-06-18T14:00:19.667 回答