Это типичный вариант использования для МОК? - PullRequest
15 голосов
/ 28 января 2010

Мое текущее приложение позволяет пользователям определять пользовательские веб-формы через набор экранов администратора. по сути это приложение типа EAV. Таким образом, я не могу жестко кодировать HTML или ASP.NET разметку для отображения данной страницы. Вместо этого пользовательский интерфейс запрашивает экземпляр объекта Form из сервисного уровня, который, в свою очередь, создает его, используя несколько таблиц RDMBS. Форма содержит классы, которые вы ожидаете увидеть в таком контексте: Form => IEnumerable<FormSections> => IEnumerable<FormFields>

Вот как выглядит сервисный слой:

public class MyFormService: IFormService{

       public Form OpenForm(int formId){
          //construct and return a concrete implementation of Form 
       }
}

Все работает великолепно (на время). Пользовательский интерфейс не является мудрым в отношении того, какие разделы / поля существуют в данной форме: он с радостью выводит объект формы, который он получает, на функциональную страницу ASP.NET.

Через несколько недель я получил новое требование от бизнеса: при просмотре нередактируемых (то есть только для чтения) версий формы определенные значения полей должны быть объединены вместе, а также должны быть добавлены другие надуманные / вычисленные поля. , Нет проблем, я говорю. Просто измените мой класс обслуживания так, чтобы его методы были более явными:

public class MyFormService: IFormService{

       public Form  OpenFormForEditing(int formId){
          //construct and return a concrete implementation of Form 
       }

       public Form  OpenFormForViewing(int formId){
          //construct and a concrete implementation of Form  
          //apply additional transformations to the form
       }
}

Опять все прекрасно работает, и сила восстановлена. Пользовательский интерфейс продолжает быть независимым от того, что находится в Форме, и наше разделение интересов достигнуто. Однако всего через несколько недель бизнес выдвигает новое требование: в определенных сценариях мы должны применять только некоторые преобразований форм, на которые я ссылался выше.

В этот момент кажется, что подход «явного метода» зашел в тупик, если только я не хочу закончить взрывом методов (OpenFormViewingScenario1, OpenFormViewingScenario2 и т. Д.). Вместо этого я ввожу еще один уровень косвенности:

public interface IFormViewCreator{
        void CreateView(Form form);
}

public class MyFormService: IFormService{

       public Form  OpenFormForEditing(int formId){
          //construct and return a concrete implementation of Form 
       }

       public Form  OpenFormForViewing(int formId, IFormViewCreator formViewCreator){
          //construct a concrete implementation of Form  
          //apply transformations to the dynamic field list
           return formViewCreator.CreateView(form);
       }
}

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

  1. У меня два вопроса: есть ли лучший способ достичь сочетаемость я после? (возможно используя контейнер IoC или дом прокатный завод для создания конкретный IFormViewCreator)?
  2. Я фундаментально испортил абстракция здесь?

Ответы [ 2 ]

9 голосов
/ 28 января 2010

Как я понимаю вопрос, вам нужно изменить Форму, прежде чем отправлять ее на уровень пользовательского интерфейса. Для меня это звучит как Decorator . Сохраните старый интерфейс IFormService без IFormViewCreator.

Теперь вы можете создать один или несколько Украшающих FormService (ов), которые реализуют желаемую фильтрацию или модификацию.

public class MyDecoratingFormService : IFormService
{
    private readonly IFormService formService;

    public MyDecoratingFormService(IFormService formService)
    {
        if(formService == null)
        {
            throw new ArgumentNullException("formService");
        }

        this.formService = formService;
    }

    public Form OpenFormForEditing(int formId)
    {
        var form = this.formService.OpenFormForEditing(formId);
        return this.TransformForm(form);
    }   

    public Form OpenFormForViewing(int formId)
    {
        var form = this.formService.OpenFormForViewing(formId);
        return this.TransformForm(form);
    }

    public Form TransformForm(Form form)
    {
        // Implement transformation/filtering/modification here
    }
}

Теперь вы можете украсить свою исходную реализацию IFormService с помощью одного или нескольких таких декораторов.

IFormService formService = new MyDecoratingFormService(new MyFormService());

Вы можете обернуть столько декораторов (каждый со своей ответственностью), сколько захотите.

Нет явной необходимости в контейнере DI, чтобы сделать это, но он прекрасно согласуется с другими шаблонами DI. Я все время пользуюсь Decorator:)

0 голосов
/ 09 февраля 2010

Если я не хочу закончить с взрыв методов (OpenFormViewingScenario1, OpenFormViewingScenario2 и т. Д.).

Вы не можете удалить присущую сложность требований. Так или иначе, вам нужно будет определить вариант использования и действовать соответственно.

Вы можете перечислить все возможные комбинации или попытаться разумно выделить обработку - если это возможно. Например, если из-за самой природы требования существует N * M = X возможностей, то исчерпывающий список методов X действительно не годится. Вы должны учесть, что необходимо создать X возможные формы из композиции N и M.

Не зная точного требования, трудно сказать. Тогда есть много возможных способов факторинга такой композиции, например, Декоратор , ChainOfResponsability , Фильтр и т. Д. Это все способы составления сложной логики.

А именно, интерфейс, который жил в невежественном блаженстве о детали реализации OpenFormForViewing, должен обладать знание и создать экземпляр IFormViewCreator.

Презентация должна быть передана форме, созданной в другом месте, чтобы оставаться независимой от создания формы. Форма, однако, должна быть где-то собрана / создана.

В MVC такая логика идет в контроллере, который обновляет модель / форму и отправляет на правильный вид / рендеринг. То же самое можно сделать с ASP.NET

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...