Определить ответственность за сохранение настроек (контроллер, сервисы и мапперы) - PullRequest
3 голосов
/ 18 января 2011

РЕДАКТИРОВАТЬ:

Поскольку я опоздал с присуждением начального вознаграждения 300 @arcain, я снова открываюсь.И присуждение дополнительных 150 @arcain.Если, конечно, кто-то не даст даже лучшего ответа.:)

/ EDIT

Рассмотрим следующую форму:

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

LocalizationService, в свою очередь, вызывает LocaleMapperDb, что-то вроде этого:

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

Где ответственность лежитдля сохранения этого параметра:

[x] let visitors browser-settings determine default language

Он будет сохранен в таблице БД с именем site_settings.Я подумал о нескольких вариантах:

  • Использование SiteService / SiteSettingsService в LocalizationController.Но затем полная форма создается и обрабатывается в LocalizationService уже.
  • Используйте SiteMapperDb / SiteSettingsMapperDb в LocalizationService и используйте его в updateCollection ($ _POST)
  • Используйте SiteMapperDb / SiteSettingsMapperDb вthe LocaleMapperDb

Первый и последний варианты выглядят как худшие, но я не уверен.Что вы считаете лучшим вариантом?Или, может быть, у вас есть альтернативный вариант, о котором я не подумал?

1 Ответ

2 голосов
/ 28 января 2011

Я думаю, что проецирование объектов модели предметной области на объекты представления модели хорошо работает в этой ситуации.

В случае с прикрепленным кодом (прошу прощения за то, что я написал его на C #; он должен быть достаточно переносимым) объекты модели домена никогда не открываются (доступ к ним осуществляется только непосредственно внутри объектов службы.) Сервисы предоставляют только представление объектами модели, такими как LocalViewModel, и этими объектами модели вида управляют контроллеры.

LocaleConfigController также отображает данные, возвращаемые сервисами, в объект LocaleConfigViewModel, и этот объект является единственным объектом, который напрямую обменивается с представлением.

Итак, в двух словах, представление имеет выделенный контроллер, и представление связывается с контроллером через объект LocaleConfigViewModel. Контроллер манипулирует объектом LocaleConfigViewModel и вызывает реализации ILocaleConfigService и ISystemConfigService. Служебные объекты никогда не выставляют модель домена контроллеру, и они отвечают за отображение объектов модели представления в объекты модели домена (с помощью любого механизма сохранения).

Обратите внимание, что служба локали - это служба конфигурации , она не будет иметь никакой реализации для поиска правильных локализованных строк. Я хотел бы поместить это в другой сервис, потому что он может быть использован в тех местах, где вы не хотите показывать какие-либо методы, которые позволили бы изменить конфигурацию локализации.

Например, на стороне управления приложением вы хотели бы иметь как службу конфигурации локализации, так и службу рендеринга строки локализации (поскольку сайт управления также может быть локализован.) нужен только сервис рендеринга строки локализации, потому что изменения конфигурации системы должны быть нежелательными и выходить за рамки этого сайта.

Итак, чтобы окончательно ответить на ваш вопрос: контроллер содержит ссылки как на локаль, так и на службы конфигурации системы, а контроллер выделен для представления - у него есть четко определенный контракт, в котором обмениваются только LocaleConfigViewModel s.

Что касается ответственности за сохранение общесистемных настроек, контроллер отвечает за распаковку системных настроек из 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; }
  // ...
}
...