设计模式 – 设计模式以避免在转换/转换期间对类型进行切换

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

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

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

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

最佳答案 经典使用访客模式.虽然您有时会看到更一般地表达模式,但这里是通过访问者模式的持久层的一些伪代码.

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

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上的代码格式很棒)

点赞