DI + UI
От: baranovda Российская Империя  
Дата: 22.06.09 07:31
Оценка:
Ещё один маленький вопросик по освоению DI. Инструментарий — .NET, Unity и WinForms

Пусть у нас есть клиентский контейнер, в котором регистрируются сервисы доступа к данным, например, экземпляр SqlConnection и сервис, инкапсулирующий некую логику работы с данными:

 

public interface IService
{
   Person GetPerson(int id);
}

public class Service : IService
{
  [Dependency]
  public SqlConnection Connection {get;set;}

  public Person GetPerson(int id)
  {
    var command = Connection.CreateCommand();
    command.CommandText = "...";
    ...
    // Конструируем Person
    Person person = new Person(reader);
    return person;
  }
}

public static void Main()
{
  var connection = new SqlConnection(connectionString);
  container.RegisterInstance<SqlConnection>(connection);
  container.RegisterType<IService, Service>();
}


Теперь собственно вопрос: какой именно объект предпочтительнее впрыскивать в экземпляры экранных форм и других самостоятельных элементов управления?

1) Сам контейнер

public class MyForm : Form
{
  [InjectionConstuctor]
  public MyForm([Dependency] IUnityContainer container) {...}
}


2) Только указатель на интерфейс сервиса

public class MyForm : Form
{
  [InjectionConstuctor]
  public MyForm([Dependency] IService service) {...}
}


4) Всё сразу и чем больше тем лучше

public class MyForm : Form
{
  [InjectionConstuctor]
  public MyForm([Dependency] IUnityContainer container) {...}

  [Dependency]
  public IService Service {get;set;}  

  [Dependency]
  public SqlConnection Connection {get;set;}
}


Спасибо за внимание
Re: DI + UI
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 22.06.09 08:39
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Ещё один маленький вопросик по освоению DI. Инструментарий — .NET, Unity и WinForms


B>Пусть у нас есть клиентский контейнер, в котором регистрируются сервисы доступа к данным, например, экземпляр SqlConnection и сервис, инкапсулирующий некую логику работы с данными:


B>
 
B>код поскипан
B>


B>Спасибо за внимание


ИМХО лучше сразу делать MVP, тогда вопросов с зависимостями не будет.
Re[2]: DI + UI
От: baranovda Российская Империя  
Дата: 22.06.09 08:49
Оценка:
Здравствуйте, gandjustas, Вы писали:

Запостил и вспомнил, что про презентеры я и забыл.

G>ИМХО лучше сразу делать MVP, тогда вопросов с зависимостями не будет.

Резонно. Но от BindingSource, которые в своём роде тоже являются презентерами, отказываться не хочу.
Спасет ли меня Composite UI Application Block?
Re[3]: DI + UI
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 22.06.09 09:09
Оценка: 1 (1)
Здравствуйте, baranovda, Вы писали:

B>Здравствуйте, gandjustas, Вы писали:


B>Запостил и вспомнил, что про презентеры я и забыл.


G>>ИМХО лучше сразу делать MVP, тогда вопросов с зависимостями не будет.

B>Резонно. Но от BindingSource, которые в своём роде тоже являются презентерами, отказываться не хочу.
Не надо отказываться.
Будет примерно так:

public class XXXForm: Form, IXXXView
{
    public XXXForm(IXXXPresenter presentr)
    {
        presenter.SetView(this); //костыль так как не поддерживаются рекурсивные зависимости
        ...
    }
 
    public void IXXXView.SetDataSourcce(..)
    {
        //настройка BindingSource
    }
}

public class XXXPresenenter: IXXXPresenter
{
    public XXXPresenenter(/*здесь все зависимости*/)
    {
        ...
    }

    ...
}



B>Спасет ли меня Composite UI Application Block?

Ну он уже давно на WPF, а если использовать WPF, то лучше MVVM.
Re[2]: DI + UI
От: Аноним  
Дата: 22.06.09 10:47
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>ИМХО лучше сразу делать MVP, тогда вопросов с зависимостями не будет.

А почему не будет?
Ведь всё равно в презентере остаётся та же самая дилема.
Передать в конструктор презентера контейнер или все необходимые сервисы или как контейнер, так и сервисы.
Re: DI + UI
От: eugen000  
Дата: 22.06.09 11:26
Оценка:
B>Теперь собственно вопрос: какой именно объект предпочтительнее впрыскивать в экземпляры экранных форм и других самостоятельных элементов управления?

B>1) Сам контейнер

B>2) Только указатель на интерфейс сервиса

B>4) Всё сразу и чем больше тем лучше


B>Спасибо за внимание


ИМХО не надо вносить зависимость на объект котейнера. Так проще тестировать и лишних зависимостей нет.
Я бы инжектил только сервис который необходим
Re[3]: DI + UI
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 22.06.09 12:28
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, gandjustas, Вы писали:


G>>ИМХО лучше сразу делать MVP, тогда вопросов с зависимостями не будет.

А>А почему не будет?
А>Ведь всё равно в презентере остаётся та же самая дилема.
А>Передать в конструктор презентера контейнер или все необходимые сервисы или как контейнер, так и сервисы.

Выделение пресентера поможет организовать зависимости, подобная организация в других слоях приведет к тому что подобные вопросы и не будут возникать.
Re[4]: DI + UI
От: baranovda Российская Империя  
Дата: 22.06.09 15:05
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Не надо отказываться.

G>Будет примерно так:

Примерно так и сделал, в башке утряслось.

Ещё маленький вопрос — всякие UI-шные прибамбасы типа курсора ожидания или перехваты исключений — это функция View или таки Presenter-а?
Re[5]: DI + UI
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 22.06.09 15:37
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Здравствуйте, gandjustas, Вы писали:


G>>Не надо отказываться.

G>>Будет примерно так:

B>Примерно так и сделал, в башке утряслось.


B>Ещё маленький вопрос — всякие UI-шные прибамбасы типа курсора ожидания или перехваты исключений — это функция View или таки Presenter-а?


Курсор — однозначно view. Пресентеру лучше вообще не знать о классах System.Windows.Forms.
Перехват исключений лучше делать в пресентере и вызывать View.ReportError(...)
Re[6]: DI + UI
От: baranovda Российская Империя  
Дата: 23.06.09 13:21
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Курсор — однозначно view. Пресентеру лучше вообще не знать о классах System.Windows.Forms.

G>Перехват исключений лучше делать в пресентере и вызывать View.ReportError(...)

А подскажи, пожалуйста, представление в модели MVP — всегда должно быть строго пассивное и презентер должен данные push-ить в него, или же представление может быть активным и тащить данные из презентера самостоятельно? Поясню на примере:

Пусть у нас есть форма редактирования атрибутов физического лица. При заполнении этой формы активным источником данных является объект типа Person, но в то же время для редактирования свойств объекта активно используются всякие справочники: пол, семейное положение и так далее. Как в модели MVP предполагается заполнять справочники?

1) Представление выставляет методы заполнения этих справочников, которые вызываются презентером:

[c#]
interface IPersonView
{
void SetGenderReferenceList(IEnumerable<Gender> list);
vois SetMaritalStatusReferenceList(IEnumerable<MaritalStatus> list);
}
[c#]

2) Представление может попросить эти справочники у самого презентера

[c#]
interface IPersonPresenter
{
IEnumerable<Gender> GetGenderReferenceList();
IEnumerable<MaritalStatus> GetMaritalStatusReferenceList();
}
[c#]

3) Представление может попросить у презентера ссылку на интерфейс, который возвращает справочные списки
4) Презентер активно проталкивает в представление интерфейс сервиса справочников
Re[7]: DI + UI
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 23.06.09 22:28
Оценка:
Здравствуйте, baranovda, Вы писали:

B>А подскажи, пожалуйста, представление в модели MVP — всегда должно быть строго пассивное и презентер должен данные push-ить в него, или же представление может быть активным и тащить данные из презентера самостоятельно? Поясню на примере:


B>Пусть у нас есть форма редактирования атрибутов физического лица. При заполнении этой формы активным источником данных является объект типа Person, но в то же время для редактирования свойств объекта активно используются всякие справочники: пол, семейное положение и так далее. Как в модели MVP предполагается заполнять справочники?


То, что вы описываете, на самом деле является двумя разновидностями MVP: с пассивным и активным видом (иногда называют push и pull view соответственно).
В первом варианте модель "спускается" виду сверху, и он её рисует. Тут часто применяют дополнительный архитектурный приём, называемый Presentation Model или View Model. Суть его очень проста — дело в том, что в реальном мире в виде редко удаётся обойтись одним объектом доменной модели. Классический пример — вид, отображающий классический заказ — который опять-таки классически состоит из объекта Order и некоторого количества объектов OrderLine. Вот тогда в игру вступает Presentation Model, который комбинирует вышеназванные объекты в один объект, скажем OrderModel, который и скармливается виду. При этом вид имеет возможность (а я бы сказал — необходимость) осуществить глубокую декомпозицию вида на составные части, при этом каждый из "дочерних" объектов отдаётся на рендеринг соответствующему "подвиду". К плюсам данного подхода относится "testing friendliness" как контроллера (ибо достаточно убедиться, что он возвращает правильную модель), так и вида (ибо вид ничего не знает о контроллере, и вообще ему всё равно, откуда эта модель берётся, что позволяет подсунуть ему специально сформированную модель из юнит-теста). Такой вариант применяется, к примеру, в ASP.NET MVC, а также вместе с библиотеками с развитыми средствами биндинга (WPF/SL).
Второй вариант — активный вид, который знает о существовании контроллера и активно это знание использует, вытягивая необходимые данные при необходимости. Честно говоря, тут я слабо представляю механизмы, ибо практического опыта применения данного подхода у меня нет, и с учётом этого подход у меня лично вызывает нехорошие ассоциации с WinForms с логикой в обработчиках ивентов... Так что отсылаю вас к статье на тему MVC на этом сайте. Если же тут есть применяющие active ("pull") view на практике — поделитесь опытом...
[КУ] оккупировала армия.
Re[7]: DI + UI
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.06.09 05:06
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Здравствуйте, gandjustas, Вы писали:


G>>Курсор — однозначно view. Пресентеру лучше вообще не знать о классах System.Windows.Forms.

G>>Перехват исключений лучше делать в пресентере и вызывать View.ReportError(...)

B>А подскажи, пожалуйста, представление в модели MVP — всегда должно быть строго пассивное и презентер должен данные push-ить в него, или же представление может быть активным и тащить данные из презентера самостоятельно? Поясню на примере:


B>Пусть у нас есть форма редактирования атрибутов физического лица. При заполнении этой формы активным источником данных является объект типа Person, но в то же время для редактирования свойств объекта активно используются всякие справочники: пол, семейное положение и так далее. Как в модели MVP предполагается заполнять справочники?



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

Что касается справочников, то нужно сделать множество во view типа SetXXXLookupData(...), смешивать push и pull не стоит.
Re[8]: DI + UI
От: Ziaw Россия  
Дата: 24.06.09 07:08
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Вариант с активным view больше похож на паттерн MVVM, он хорошо работает когда есть декларативный байндинг и в нем можно достаточно сложные функциональные зависимости выражать. В отсутствии такого байндинга лучше делать view пассивным, чтобы весь важный код был в пресентере (там его легче тестировать).


G>Что касается справочников, то нужно сделать множество во view типа SetXXXLookupData(...), смешивать push и pull не стоит.


Интересно, вот я использую пассивный view в винформсах, но передача активностей через события меня сильно парит. Посему решено делать вместо событий прямые вызовы методов презентера. Ибо это проще тестируется и требует меньше кода. Я смешал push и pull? Какие минусы в таком подходе?
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Re[9]: DI + UI
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.06.09 07:36
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Здравствуйте, gandjustas, Вы писали:


G>>Вариант с активным view больше похож на паттерн MVVM, он хорошо работает когда есть декларативный байндинг и в нем можно достаточно сложные функциональные зависимости выражать. В отсутствии такого байндинга лучше делать view пассивным, чтобы весь важный код был в пресентере (там его легче тестировать).


G>>Что касается справочников, то нужно сделать множество во view типа SetXXXLookupData(...), смешивать push и pull не стоит.


Z>Интересно, вот я использую пассивный view в винформсах, но передача активностей через события меня сильно парит. Посему решено делать вместо событий прямые вызовы методов презентера. Ибо это проще тестируется и требует меньше кода. Я смешал push и pull? Какие минусы в таком подходе?

можно код? а то на словах не очень понятно.
Re[10]: DI + UI
От: Ziaw Россия  
Дата: 24.06.09 07:52
Оценка:
Здравствуйте, gandjustas, Вы писали:


G>можно код? а то на словах не очень понятно.



мой вариант:

interface IMyView
{
  string Data {get;set;}
}

class MyView: Form, IMyView
{
  string Data 
  {
        get { return dataTextBox.Text; }
        set { dataTextBox.Text = value; }
    }
    
    public MyView()
    {
        InitializeControls();
        var presenter = new MyPresenter(this); 
        saveButton.Click += (_, __) => presenter.Save();
        presenter.Load();
    }
}

class MyPresneter
{
  readonly IMyView myView;
  
  public MyPresneter(IMyView View)
  {
    myView = view;
  }
  
  public void Load()
  {
        view.Data = someSevice.GetData();
  }
  
  public void Save()
  {
        var data = view.Data;
        Validate(data);
        someSevice.SaveData(data);
  }
}


истинно пассивная вью:

interface IMyView
{
  string Data {get;set;}
  event Action Loading;
  event Action Saving;
}

class MyView: Form, IMyView
{
  string Data 
  {
        get { return dataTextBox.Text; }
        set { dataTextBox.Text = value; }
    }
  public event Action Loading;
  public event Action Saving;
    
    public MyView()
    {
        InitializeControls();
        var presenter = new MyPresenter(this); 
        saveButton.Click += OnSave;
        OnLoad();
    }
    
    void OnSave(object sender, EventArgs e)
    {
        if (Saving != null)
            Saving();
    }

    void OnLoad(object sender, EventArgs e)
    {
        if (Loading != null)
            Loading();
    }
}

class MyPresneter
{
  readonly IMyView myView;
  
  public MyPresneter(IMyView View)
  {
    myView = view;
    myView.Loading += Load;
    myView.Saving += Save;
  }
  
  public void Load()
  {
        view.Data = someSevice.GetData();
  }
  
  public void Save()
  {
        var data = view.Data;
        Validate(data);
        someSevice.SaveData(data);
  }
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Re[11]: DI + UI
От: baranovda Российская Империя  
Дата: 24.06.09 07:59
Оценка:
Здравствуйте, Ziaw, Вы писали:

Во многих статьях про MVP авторы осторожно утверждают, что комбинирование View и Presenter-а какбе допустимо, но не рекомендуемо, потому что можно легко запутаться и утерять преимущества декомпозиции
Re[11]: DI + UI
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.06.09 08:03
Оценка:
Здравствуйте, Ziaw, Вы писали:

Вариант с "истинно пассивной view" уже на грани бреда.
Никаких преимуществ в плане decopuling не дает.


Так что первый вариант вполне хорош. Кстати push модель в нем не нарушена.
Re[12]: DI + UI
От: Ziaw Россия  
Дата: 24.06.09 08:06
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Вариант с "истинно пассивной view" уже на грани бреда.

G>Никаких преимуществ в плане decopuling не дает.

Я пришел к тому же мнению.
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Re[12]: DI + UI
От: Ziaw Россия  
Дата: 24.06.09 08:06
Оценка:
Здравствуйте, baranovda, Вы писали:

B>Здравствуйте, Ziaw, Вы писали:


B>Во многих статьях про MVP авторы осторожно утверждают, что комбинирование View и Presenter-а какбе допустимо, но не рекомендуемо, потому что можно легко запутаться и утерять преимущества декомпозиции


М... а где здесь комбинирование?
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Re[13]: DI + UI
От: baranovda Российская Империя  
Дата: 24.06.09 08:12
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>М... а где здесь комбинирование?


Если View знает о Presenter, а Presenter — о View, то, например, у меня вчера возникло непонимание и желание слить их воедино

http://www.rsdn.ru/article/patterns/ModelViewPresenter.xml
Автор(ы): Иван Бодягин
Дата: 25.07.2006
В наше время сложно найти разработчика, который не слышал бы о паттерне под названием Model-View-Controller или сокращенно MVC, что вообщем не удивительно, с задачей отделения данных от их представления сталкиваешься практически на каждом проекте. Однако, как ни странно, столь же сложно найти разработчика, который действительно четко себе представляет, что такое на самом деле паттерн MVC и как его можно реализовать в конкретной ситуации. Основная причина такой неоднозначности в том, что по историческим причинам данной аббревиатурой принято называть не один единственный паттерн, а целое семейство паттернов, призванное отделять представление от модели. Произошло это в силу разных обстоятельств. Отчасти из-за того что MVC не просто паттерн, а довольно объемное архитектурное решение, в котором каждый новый разработчик видел что-то свое и ставя во главу угла особенности своего проекта, реализовывал его по своему. Отчасти же из-за возраста данного паттерна, во времена его изобретения и сами приложения, и графические интерфейсы были существенно беднее чем в наше время, с тех пор они сильно эволюционировали и вместе с ними изменялся и сам паттерн. Данная статья посвящена также одному из паттернов входящих в это семейство, причинам его появления, особенностям применения, преимуществам и недостаткам, а так же описанию сопутствующих паттернов.

В этой версии MVC Контроллер интегрирован в Представление, что ни в коей мере не является нарушением основной идеи паттерна.

(правда, тут речь идёт о MVC)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.