Ещё один маленький вопросик по освоению 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;}
}
Здравствуйте, baranovda, Вы писали:
B>Ещё один маленький вопросик по освоению DI. Инструментарий — .NET, Unity и WinForms
B>Пусть у нас есть клиентский контейнер, в котором регистрируются сервисы доступа к данным, например, экземпляр SqlConnection и сервис, инкапсулирующий некую логику работы с данными:
B>
B>код поскипан
B>
B>Спасибо за внимание
ИМХО лучше сразу делать MVP, тогда вопросов с зависимостями не будет.
Запостил и вспомнил, что про презентеры я и забыл.
G>ИМХО лучше сразу делать MVP, тогда вопросов с зависимостями не будет.
Резонно. Но от BindingSource, которые в своём роде тоже являются презентерами, отказываться не хочу.
Спасет ли меня Composite UI Application Block?
Здравствуйте, 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, тогда вопросов с зависимостями не будет.
А почему не будет?
Ведь всё равно в презентере остаётся та же самая дилема.
Передать в конструктор презентера контейнер или все необходимые сервисы или как контейнер, так и сервисы.
B>Теперь собственно вопрос: какой именно объект предпочтительнее впрыскивать в экземпляры экранных форм и других самостоятельных элементов управления?
B>1) Сам контейнер B>2) Только указатель на интерфейс сервиса
B>4) Всё сразу и чем больше тем лучше
B>Спасибо за внимание
ИМХО не надо вносить зависимость на объект котейнера. Так проще тестировать и лишних зависимостей нет.
Я бы инжектил только сервис который необходим
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, gandjustas, Вы писали:
G>>ИМХО лучше сразу делать MVP, тогда вопросов с зависимостями не будет. А>А почему не будет? А>Ведь всё равно в презентере остаётся та же самая дилема. А>Передать в конструктор презентера контейнер или все необходимые сервисы или как контейнер, так и сервисы.
Выделение пресентера поможет организовать зависимости, подобная организация в других слоях приведет к тому что подобные вопросы и не будут возникать.
Здравствуйте, baranovda, Вы писали:
B>Здравствуйте, gandjustas, Вы писали:
G>>Не надо отказываться. G>>Будет примерно так:
B>Примерно так и сделал, в башке утряслось.
B>Ещё маленький вопрос — всякие UI-шные прибамбасы типа курсора ожидания или перехваты исключений — это функция View или таки Presenter-а?
Курсор — однозначно view. Пресентеру лучше вообще не знать о классах System.Windows.Forms.
Перехват исключений лучше делать в пресентере и вызывать View.ReportError(...)
Здравствуйте, gandjustas, Вы писали:
G>Курсор — однозначно view. Пресентеру лучше вообще не знать о классах System.Windows.Forms. G>Перехват исключений лучше делать в пресентере и вызывать View.ReportError(...)
А подскажи, пожалуйста, представление в модели MVP — всегда должно быть строго пассивное и презентер должен данные push-ить в него, или же представление может быть активным и тащить данные из презентера самостоятельно? Поясню на примере:
Пусть у нас есть форма редактирования атрибутов физического лица. При заполнении этой формы активным источником данных является объект типа Person, но в то же время для редактирования свойств объекта активно используются всякие справочники: пол, семейное положение и так далее. Как в модели MVP предполагается заполнять справочники?
1) Представление выставляет методы заполнения этих справочников, которые вызываются презентером:
3) Представление может попросить у презентера ссылку на интерфейс, который возвращает справочные списки
4) Презентер активно проталкивает в представление интерфейс сервиса справочников
Здравствуйте, 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 на практике — поделитесь опытом...
Здравствуйте, baranovda, Вы писали:
B>Здравствуйте, gandjustas, Вы писали:
G>>Курсор — однозначно view. Пресентеру лучше вообще не знать о классах System.Windows.Forms. G>>Перехват исключений лучше делать в пресентере и вызывать View.ReportError(...)
B>А подскажи, пожалуйста, представление в модели MVP — всегда должно быть строго пассивное и презентер должен данные push-ить в него, или же представление может быть активным и тащить данные из презентера самостоятельно? Поясню на примере:
B>Пусть у нас есть форма редактирования атрибутов физического лица. При заполнении этой формы активным источником данных является объект типа Person, но в то же время для редактирования свойств объекта активно используются всякие справочники: пол, семейное положение и так далее. Как в модели MVP предполагается заполнять справочники?
Вариант с активным view больше похож на паттерн MVVM, он хорошо работает когда есть декларативный байндинг и в нем можно достаточно сложные функциональные зависимости выражать. В отсутствии такого байндинга лучше делать view пассивным, чтобы весь важный код был в пресентере (там его легче тестировать).
Что касается справочников, то нужно сделать множество во view типа SetXXXLookupData(...), смешивать push и pull не стоит.
Здравствуйте, gandjustas, Вы писали:
G>Вариант с активным view больше похож на паттерн MVVM, он хорошо работает когда есть декларативный байндинг и в нем можно достаточно сложные функциональные зависимости выражать. В отсутствии такого байндинга лучше делать view пассивным, чтобы весь важный код был в пресентере (там его легче тестировать).
G>Что касается справочников, то нужно сделать множество во view типа SetXXXLookupData(...), смешивать push и pull не стоит.
Интересно, вот я использую пассивный view в винформсах, но передача активностей через события меня сильно парит. Посему решено делать вместо событий прямые вызовы методов презентера. Ибо это проще тестируется и требует меньше кода. Я смешал push и pull? Какие минусы в таком подходе?
Здравствуйте, Ziaw, Вы писали:
Z>Здравствуйте, gandjustas, Вы писали:
G>>Вариант с активным view больше похож на паттерн MVVM, он хорошо работает когда есть декларативный байндинг и в нем можно достаточно сложные функциональные зависимости выражать. В отсутствии такого байндинга лучше делать view пассивным, чтобы весь важный код был в пресентере (там его легче тестировать).
G>>Что касается справочников, то нужно сделать множество во view типа SetXXXLookupData(...), смешивать push и pull не стоит.
Z>Интересно, вот я использую пассивный view в винформсах, но передача активностей через события меня сильно парит. Посему решено делать вместо событий прямые вызовы методов презентера. Ибо это проще тестируется и требует меньше кода. Я смешал push и pull? Какие минусы в таком подходе?
можно код? а то на словах не очень понятно.
Во многих статьях про MVP авторы осторожно утверждают, что комбинирование View и Presenter-а какбе допустимо, но не рекомендуемо, потому что можно легко запутаться и утерять преимущества декомпозиции
Здравствуйте, baranovda, Вы писали:
B>Здравствуйте, Ziaw, Вы писали:
B>Во многих статьях про MVP авторы осторожно утверждают, что комбинирование View и Presenter-а какбе допустимо, но не рекомендуемо, потому что можно легко запутаться и утерять преимущества декомпозиции
Здравствуйте, baranovda, Вы писали:
B>Если View знает о Presenter, а Presenter — о View, то, например, у меня вчера возникло непонимание и желание слить их воедино
Неверно, view знает о презентере, это нормально, у нее один вполне реальный презентер и дальнейших вариантов работы этой view с другим презентером я не представляю. Презентер же знает только об интерфейсе view. Посему его легко тестировать подсовывая собственные реализации этого интерфейса. Слив их воедино мы лишаемся четкого разделения логики представления и БЛ. И лишаемся юнит тестирования обеих.
B>http://www.rsdn.ru/article/patterns/ModelViewPresenter.xml
Здравствуйте, gandjustas, Вы писали:
B>>Резонно. Но от BindingSource, которые в своём роде тоже являются презентерами, отказываться не хочу. G>Не надо отказываться. G>Будет примерно так:
G>
G>public class XXXForm: Form, IXXXView
G>{
G> public XXXForm(IXXXPresenter presentr)
G> {
G> presenter.SetView(this); //костыль так как не поддерживаются рекурсивные зависимости
G> ...
G> }
G> public void IXXXView.SetDataSourcce(..)
G> {
G> //настройка BindingSource
G> }
G>}
G>public class XXXPresenenter: IXXXPresenter
G>{
G> public XXXPresenenter(/*здесь все зависимости*/)
G> {
G> ...
G> }
G> ...
G>}
G>
Сорри за глупый вопрос, но у меня почему-то не утряслось в башке
для public void IXXXView.SetDataSourcce(..), что должно стать параметром?
Z>Сорри за глупый вопрос, но у меня почему-то не утряслось в башке Z>для public void IXXXView.SetDataSourcce(..), что должно стать параметром?
Я думаю можно BindingSource.
Здравствуйте, Ziggi111, Вы писали:
Z>Сорри за глупый вопрос, но у меня почему-то не утряслось в башке Z>для public void IXXXView.SetDataSourcce(..), что должно стать параметром?
Коллекция объектов или DataSet данные из которых надо связывать с контролами.
Здравствуйте, Dog, Вы писали:
Z>>Сорри за глупый вопрос, но у меня почему-то не утряслось в башке Z>>для public void IXXXView.SetDataSourcce(..), что должно стать параметром? Dog>Я думаю можно BindingSource.
ничего не понял.
Если не использовать никаких паттернов, то получается примерно такой код
this.myBindingSource.DataSource = typeof (myType);
this.label1.DataBindings.Add (new System.Windows.Forms.Binding ("Text", this.myBindingSource, "Property1", true));
this.Text1.DataBindings.Add (new System.Windows.Forms.Binding ("Text", this.myBindingSource, "Property2", true));
если мы напишем
public void IXXXView.SetDataSourcce(BindingSource myBindingSource)
{
//То что тогда здесь?
}
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Ziggi111, Вы писали:
Z>>Сорри за глупый вопрос, но у меня почему-то не утряслось в башке Z>>для public void IXXXView.SetDataSourcce(..), что должно стать параметром?
G>Коллекция объектов или DataSet данные из которых надо связывать с контролами.
или объект модели, если мы редактируем один объект. так?
но ведб если это так, то получается, что View знает о модели. или я что-то путаю?
Здравствуйте, Ziggi111, Вы писали:
Z>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, Ziggi111, Вы писали:
Z>>>Сорри за глупый вопрос, но у меня почему-то не утряслось в башке Z>>>для public void IXXXView.SetDataSourcce(..), что должно стать параметром?
G>>Коллекция объектов или DataSet данные из которых надо связывать с контролами. Z>или объект модели, если мы редактируем один объект. так?
ага
Z>но ведб если это так, то получается, что View знает о модели. или я что-то путаю?
Не знает. Данные — это не "модель".
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Ziggi111, Вы писали:
Z>>Здравствуйте, gandjustas, Вы писали:
G>>>Здравствуйте, Ziggi111, Вы писали:
Z>>>>Сорри за глупый вопрос, но у меня почему-то не утряслось в башке Z>>>>для public void IXXXView.SetDataSourcce(..), что должно стать параметром?
G>>>Коллекция объектов или DataSet данные из которых надо связывать с контролами. Z>>или объект модели, если мы редактируем один объект. так? G>ага
Z>>но ведб если это так, то получается, что View знает о модели. или я что-то путаю? G>Не знает. Данные — это не "модель".
получается что на самой форме все останется как и было, т.е. в дизайнере проставляем контролам BindingSource, самому BindingSource проставляем DataSource и т.д.
а в этом методе просто пишем
public void IXXXView.SetDataSourcce(MyClass Value)
{
BindingSource.DataSource = Value;
}
Здравствуйте, Ziggi111, Вы писали:
Z>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, Ziggi111, Вы писали:
Z>>>Здравствуйте, gandjustas, Вы писали:
G>>>>Здравствуйте, Ziggi111, Вы писали:
Z>>>>>Сорри за глупый вопрос, но у меня почему-то не утряслось в башке Z>>>>>для public void IXXXView.SetDataSourcce(..), что должно стать параметром?
G>>>>Коллекция объектов или DataSet данные из которых надо связывать с контролами. Z>>>или объект модели, если мы редактируем один объект. так? G>>ага
Z>>>но ведб если это так, то получается, что View знает о модели. или я что-то путаю? G>>Не знает. Данные — это не "модель".
Z>получается что на самой форме все останется как и было, т.е. в дизайнере проставляем контролам BindingSource, самому BindingSource проставляем DataSource и т.д. Z>а в этом методе просто пишем
Z>
Здравствуйте, Dog, Вы писали:
Dog>>>Я думаю можно BindingSource. Z>>ничего не понял. Z>>Если не использовать никаких паттернов, то получается примерно такой код Z>>
Z>>this.myBindingSource.DataSource = typeof (myType);
Z>>this.label1.DataBindings.Add (new System.Windows.Forms.Binding ("Text", this.myBindingSource, "Property1", true));
Z>>this.Text1.DataBindings.Add (new System.Windows.Forms.Binding ("Text", this.myBindingSource, "Property2", true));
Z>>
Z>>если мы напишем Z>>
Z>>public void IXXXView.SetDataSourcce(BindingSource myBindingSource)
Z>>{
Z>> //То что тогда здесь?
Z>>}
Z>>
Dog>
Ну да, у меня тоже такая мысль была, но мне нужно было просто уложить окончательно всё в голове
Наверно делать буду именно так. Не могу объяснить почему, но почему-то кажется что так красивше
Здравствуйте, gandjustas, Вы писали:
сорри, а не могли бы Вы немного помочь в осмыслении некоторых вещей. могли бы мы с Вами пообчаться помимо форума(ася, почта etc)