确定保存设置的责任(控制器,服务和映射器)

时间:2011-01-17 22:01:22

标签: model-view-controller language-agnostic service datamapper responsibility

修改

因为我很晚才将300的最初赏金授予@arcain,我正在重新开放。并将额外的150授予@arcain。除非有人提供更好的答案。 :)

/编辑

考虑以下形式:

language | region | active | default |
-----------------------------------------------
en       | GB     | [x]    | (*)     | [X delete]
nl       | NL     | [x]    | ( )     | [X delete]
nl       | BE     | [x]    | ( )     | [X delete]

[x] let visitors browser-settings determine the default language

[save]

上表的设置将保存在数据库表中,其中列映射到上面的列(显然不包括最后一列)。

所有(保存和删除)操作直接指向本地化控制器。 Localization控制器基本上调用LocalizationService上的方法,如下所示:

$localizationService->updateCollection( $_POST ) // update collection settings
// or
$localizationService->delete( $_POST ) // delete a single locale

本地化服务转而调用LocaleMapperDb,如下所示:

foreach( $localeCollection as $locale )
{
    $localeMapperDb->update( LocaleModel $locale );
}
// or
$localeMapperDb->delete( LocaleModel $locale );

但是,保存此设置的责任在哪里:

[x] let visitors browser-settings determine default language

它将保存在名为site_settings的数据库表中。我想到了几个选择:

  • 在LocalizationController中使用SiteService / SiteSettingsService。但是,完整的表单已经在LocalizationService中生成和处理。
  • 在LocalizationService中使用SiteMapperDb / SiteSettingsMapperDb并在updateCollection中使用它($ _POST)
  • 在LocaleMapperDb中使用SiteMapperDb / SiteSettingsMapperDb

第一个和最后一个选项看起来是最差的选项,但我不确定。你觉得什么是最好的选择?或者你可能有另一种选择,我没有想过?

1 个答案:

答案 0 :(得分:2)

我认为将域模型对象投影到视图模型对象上可以很好地适应这种情况。

对于附加代码(请原谅我在C#中编写它;它应该是相当可移植的)域模型对象永远不会公开(它们只能在服务对象中直接访问。)服务只公开视图模型对象,如LocalViewModel,这些视图模型对象由控制器操纵。

LocaleConfigController还将服务返回的数据映射到LocaleConfigViewModel对象,并且该对象是与视图直接交换的唯一对象。

因此,简而言之,视图具有专用控制器,视图通过LocaleConfigViewModel对象与控制器通信。控制器操纵LocaleConfigViewModel对象并调用ILocaleConfigServiceISystemConfigService的实现。服务对象永远不会将域模型暴露给控制器,它们负责将视图模型对象映射到域模型对象(通过任何需要的持久性机制。)

请注意,语言环境服务是配置服务,它没有任何实现来查找正确的本地化字符串。我会把它放到另一个服务中,因为它可以在你不想暴露任何允许更改本地化配置的方法的地方使用。

例如,在应用程序的管理方面,您可能需要本地化配置服务和本地化字符串呈现服务(因为管理站点也可以进行本地化。)对于面向前端的客户,您可能会改为只需要本地化字符串呈现服务,因为系统配置修改应该是不需要的并且超出该站点的范围。

所以,最后回答你的问题:控制器包含对语言环境和系统配置服务的引用,控制器专用于视图 - 它有一个明确定义的合同,其中只有LocaleConfigViewModel是交换。

至于保存系统范围设置的责任在哪里,控制器负责从LocaleConfigViewModel解压缩系统设置并将它们推送到适当的服务中(在这种情况下为ISystemConfigService例如)它们将被保留。

class LocaleViewModel
{
  public int Id;
  public string Language;
  public string Region;
  public bool Enabled;
  public bool Deleted;
}

class LocaleConfigViewModel
{
  public bool UseVisitorBrowserLocale;
  public LocaleViewModel DefaultLocale;
  public List<LocaleViewModel> Locales; 
}

class LocaleConfigController : ILocaleConfigController
{
  ILocaleConfigService localeConfig;
  ISystemConfigService systemConfig;

  public void Save(LocaleConfigViewModel model)
  {
    foreach (var locale in model.Locales)
    {
      if (locale.Deleted)
      {
        localeConfig.DeleteLocale(locale);
        continue;
      }
      localeConfig.UpdateLocale(locale);
    }
    systemConfig.DefaultLocaleId = model.DefaultLocale.Id;
    systemConfig.UseVisitorBrowserLocale = model.UseVisitorBrowserLocale;
  }

  public LocaleConfigViewModel GetCurrentView()
  {
    var model = new LocaleConfigViewModel();
    model.Locales = localeConfig.Locales;
    model.DefaultLocale = model.Locales.FirstOrDefault(l => l.Id == systemConfig.DefaultLocaleId);
    model.UseVisitorBrowserLocale = systemConfig.UseVisitorBrowserLocale;
    return model;
  }

  // ...
}

interface ILocaleConfigController
{
  void Save(LocaleConfigViewModel model);
  LocaleConfigViewModel GetCurrentView();
  // ... 
}

interface ILocaleConfigService // services will be stateless and threadsafe
{
  void DeleteLocale(LocaleViewModel locale);
  void UpdateLocale(LocaleViewModel locale);
  List<LocaleViewModel> Locales { get; }
  // ...
}

interface ISystemConfigService // services will be stateless and threadsafe
{
  int DefaultLocaleId { get; set; }
  bool UseVisitorBrowserLocale { get; set; }
  // ...
}