Я думаю, что проецирование объектов модели предметной области на объекты представления модели хорошо работает в этой ситуации.
В случае с прикрепленным кодом (прошу прощения за то, что я написал его на 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; }
// ...
}