Определить ответственность за сохранение настроек (контроллер, сервисы и мапперы)
РЕДАКТИРОВАТЬ:
Потому что я опоздал с начальным награждением 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
Сервис 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 в LocaleMapperDb
Первый и последний варианты выглядят как худшие, но я не уверен. Что вы считаете лучшим вариантом? Или, может быть, у вас есть альтернативный вариант, я не подумал?
1 ответ
Я думаю, что проецирование объектов модели предметной области на объекты модели представления хорошо работает в этой ситуации.
В случае с прикрепленным кодом (прошу прощения, что написал его на C#; он должен быть достаточно переносимым), объекты модели домена никогда не открываются (доступ к ним осуществляется только непосредственно внутри объектов службы.) Сервисы предоставляют только объекты модели представления, лайк LocalViewModel
и этими объектами модели представления управляют контроллеры.
LocaleConfigController
также отображает данные, возвращаемые службами в LocaleConfigViewModel
объект, и этот объект является единственным объектом, который обменивается непосредственно с представлением.
Итак, в двух словах, представление имеет выделенный контроллер, и представление связывается с контроллером через LocaleConfigViewModel
объект. Контроллер манипулирует LocaleConfigViewModel
объект и вызывает в реализации ILocaleConfigService
и ISystemConfigService
, Служебные объекты никогда не предоставляют модель домена контроллеру, и они отвечают за отображение объектов модели представления в объекты модели домена (с помощью любого механизма сохранения).
Обратите внимание, что служба локали - это служба конфигурации, она не будет иметь никакой реализации для поиска правильных локализованных строк. Я хотел бы поместить это в другой сервис, потому что он может быть использован в тех местах, где вы не хотите показывать какие-либо методы, которые позволили бы изменить конфигурацию локализации.
Например, на стороне управления приложением вы хотели бы использовать как службу конфигурации локализации, так и службу рендеринга строки локализации (поскольку сайт управления также может быть локализован). Для клиентского интерфейса пользователь, скорее всего, захочет только сервис рендеринга строки локализации, потому что изменения конфигурации системы должны быть нежелательными и выходить за рамки этого сайта.
Итак, чтобы окончательно ответить на ваш вопрос: контроллер содержит ссылки как на локаль, так и на службы конфигурации системы, а контроллер выделен для представления - у него есть четко определенный контракт, в котором только 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; }
// ...
}