Обобщенный Model-View-Controller
От: Сергей Рогачев Россия http://rsn81.wordpress.com
Дата: 23.03.07 04:21
Оценка: 231 (15) +1 -2
Статья:
Обобщенный Model-View-Controller
Автор(ы): Сергей Рогачев
Дата: 23.03.2007
В статье рассматривается вариант реализации шаблона проектирования Model-View-Controller в виде каркаса приложения на основе обобщенного программирования языков Java и C#. В описании предлагаемого решения, кроме того, будут рассмотрены шаблоны проектирования Mediator, Observer и Command и показаны варианты их применения в рассматриваемой реализации Model-View-Controller. Предполагается наличие у читателя знания базовых шаблонов проектирования, языка UML, диаграммами которого будут сопровождаться описания, а также одного из указанных языков программирования.


Авторы:
Сергей Рогачев

Аннотация:
В статье рассматривается реализация шаблона проектирования Model-View-Controller на основе обобщенного программирования языков Java и C#. В описании предлагаемого решения, кроме того, будут рассмотрены шаблоны проектирования Mediator, Observer и Command. Предполагается наличие у читателя знания базовых шаблонов проектирования, языка UML, диаграммами которого будут сопровождаться описания, а также одного из указанных языков программирования.
Re[2]: Обобщенный Model-View-Controller
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 29.03.07 17:43
Оценка: 9 (3)
Здравствуйте, Дмитрий В, Вы писали:

Во-первых, эта "нераскрытость" несколько другой тематики, например, что-то вроде Признаки плохого кода
Автор(ы): Джошуа Кериевски
Дата: 31.10.2006
Глава из книги "Рефакторинг с использованием шаблонов".
Наиболее распространенные проблемы проектов возникают в следующих случаях:
— если код содержит повторы;
— если он непонятен;
— если он сложен.
Эти критерии определенно могут помочь обнаружить в коде места, нуждающиеся в улучшении. С другой стороны, многие программисты считают этот список слишком неопределенным: не понятно, как опознать в коде повторения, если они не совсем одинаковы; невозможно с полной уверенностью судить, ясно ли говорит код о своем назначении, не понятно, как отличить простой код от сложного.
, Почему ваш код — отстой
Автор(ы): Дейв Эстелс (Dave Astels)
Дата: 13.06.2006
Если Вы программируете как большинство, и даже, вероятно, все программисты (скромненько включая автора этой статьи), то ваш код – отстой. Возможно, не целиком; возможно, не всегда, но наверняка какая-то его часть и в какой-то момент времени.
и т.п. — мне нравится в этом отношении статья О потерянном уровне. В обсуждаемой же статье, как и обычно, приведены шаблоны как решения типовых задач, то есть четко сказано, где они применяются и какой выигрыш дают. Мне кажется излишним приводить листинг "бездумного" кода, это, как понимаете, в отличие от шаблонов слишком многовариантно, хотя в книге по первой ссылке это и попытались сделать.

Во-вторых, давно уже склоняюсь к мысли, что до необходимости применения шаблонов проектирования на практике разработчик должен дойти своим умом. Пока человек сам не столкнется с проблемой, пока самостоятельно, следуя внутреннему решению, а не указке, не начнет искать готовые решения — его не стоит учить шаблонам. Иначе человек наверняка, во-первых, будет использовать шаблоны, как студент технического ВУЗа методичку — бездумно используя их, где надо и не надо, а во-вторых, навсегда похоронит в себе архитектора: шаблоны — это типовые решения, опыт накопленный другими разработчиками, и используя шаблоны человек не должен переставать думать, и, возможно, изобретать в конкретных специфических задачах свои собственные шаблоны. То есть использовать шаблоны проектирования, конечно, нужно, но тогда, когда подсказывает собственный опыт — иначе есть опасность применения шаблонов в том месте, где они только навредят.

В подтверждение последнего анекдот собственной жизни. В свое время сразу после университета, в ту пору, когда каждый студент думает, что он знает и может все, опробовал на своем собственном лбу n-количество граблей, после чего нашел несколько, как мне тогда показалось, гениальных решений. И каким же было мое изумление, когда позже в период переосмысления своих завышенных в студенчестве возможностей, я узнал, что, оказывается, ничто не ново под Луной. Оказалось, что моим "гениальным решениям" (насколько помню, использовал тогда жуткие собственные интерпретации AbstractFactory, State, Decorator, Adapter, Command, Observer, Singleton, Mapper, Memento и что-то еще, все не упомнить... особенно то, как я сам их называл, хотя скорее всего просто интуитивно применял без формализации и классификации) сто лет в обед, называются они шаблонами проектирования, имеют "умные" названия и классификацию. Жутко тогда расстроился, а потом подумал, посмеялся... и понял, что именно такой путь и нужно проделать на пути проектирования: дойти своими мозгами хотя бы до постановки проблемы, четко ее сформулировать самому себе, а вот только после этого смотреть готовые решения этой проблемы.
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re: Обобщенный Model-View-Controller
От: ALSK  
Дата: 22.06.07 12:38
Оценка: 13 (2)
Здравствуйте, Сергей Рогачев, Вы писали:

СР>Статья:

СР>Обобщенный Model-View-Controller
Автор(ы): Сергей Рогачев
Дата: 23.03.2007
В статье рассматривается вариант реализации шаблона проектирования Model-View-Controller в виде каркаса приложения на основе обобщенного программирования языков Java и C#. В описании предлагаемого решения, кроме того, будут рассмотрены шаблоны проектирования Mediator, Observer и Command и показаны варианты их применения в рассматриваемой реализации Model-View-Controller. Предполагается наличие у читателя знания базовых шаблонов проектирования, языка UML, диаграммами которого будут сопровождаться описания, а также одного из указанных языков программирования.


Материал изложен четко, просто, и может быть весьма полезен, но ряд аспектов значительно ухудшают впечатление.
Далее все примеры кода написаны на псевдо-С++.

1. Гневный памфлет о Command.

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

Рассмотрим эту реализацию.
По GoF шаблон Command призван инкапсулировать запрос. Отсюда вытекают два основных признака Команды:
1) клиент Команды абстрагируется от получателя запроса
2) клиент Команды абстрагируется от вызываемой операции
Из этих признаков следует возможность параметризации клиента запросом, что является основным применением шаблона Команда.
Перепишем реализацию, приведенную в статье, в упрощенном виде:

enum O { OPCODE1, OPCODE2, OPCODE3 }
class Controller {
public:
    void execute(O operation, P attribute) 
        {
        switch (operation) {
        case OPCODE1:
            DoSomething1; 
        case OPCODE2:
            DoSomething2; 
        case OPCODE3:
            DoSomething3; 
        default:
            AbortAll();
        }
    }
}
class View {
public:
    void edit1(P attribute) 
        { controller->execute(OPCODE1);    }
    void edit2(P attribute) 
        { controller->execute(OPCODE2);    }
    void edit3(P attribute) 
        { controller->execute(OPCODE3);    }
private:
    Controller* controller;
}


Никто нам не помешает любой кусок кода вынести в отдельную функцию. Преобразуем код еще немного:
enum O { OPCODE1, OPCODE2, OPCODE3 }
class Controller {
public:
    void execute(O operation, P attribute) 
        {
        switch (operation) {
        case OPCODE1:
            f1(attribute); 
        case OPCODE2:
            f2(attribute) 
        case OPCODE3:
            f3(attribute); 
        default:
            AbortAll();
        }
    }
private:
    void f1(P attribute) { DoSomething1; }
    void f2(P attribute) { DoSomething2; }
    void f3(P attribute) { DoSomething3; }
}
class View {
public:
    void edit1(P attribute) 
        { controller->execute(OPCODE1, attribute); }
    void edit2(P attribute) 
        { controller->execute(OPCODE2, attribute); }
    void edit3(P attribute) 
        { controller->execute(OPCODE3, attribute); }
private:
    Controller* controller;
}


Теперь, взглянув незамутненным взором, можно увидеть, что реализация в статье шаблона Command, является всего лишь косвенным вызовом методов класса с помощью кодов этих методов. Для простоты так и будем дальше называть этот прием "вызов методов по их коду". В качестве кода метода может использоваться что угодно — enum, int, строка и т.д.

Посмотрим выполняются ли признаки Command для этой реализации:
1) клиент НЕ абстрагируется от получателя запроса, т.к класс View хранит прямую ссылку на контроллер и вызывает его операции. То, что контроллер является не конечным получателем, а всего лишь посредником, не важно. Мы обсуждаем шаблон Command, и является ли получатель Mediator'ом или еще какой фабрикой, нас не должно заботить.
2) клиент НЕ абстрагируется от вызываемой операции, т.к View вызывает конкретные методы контроллера, используя конкретный код этого метода. Какой метод контроллера вызвать решает View и только View.

Обобщая дальше, вспомним, что открытый интерфейс класса — это по сути набор внешних сообщений, которые может обрабатывать экземпляр класса. К примеру, набор открытых (public) методов класса View edit1, edit2, edit3+ их сигнатуры является открытым интерфейсом класса. Но таким образом, набор кодов методов в виде OPCODE1, OPCODE2, OPCODE3 + метод execute и ее сигнатура являются открытым интерфейсом класса Controller.
Поэтому назвать обращение экземпляров класса View к экземплярам класса Controller через его открытый интерфейс "шаблоном проектирования" язык не поворачивается. И косвенный вызов методов по их кодам можно без всяких последствий заменить прямым вызовом методов.
class Controller {
public:
    void f1(P attribute) { DoSomething1; }
    void f2(P attribute) { DoSomething2; }
    void f3(P attribute) { DoSomething3; }
}
class View {
public:
    void edit1(P attribute) 
        { controller->f1(attribute); }
    void edit2(P attribute) 
        { controller->f2(attribute); }
    void edit3(P attribute) 
        { controller->f3(attribute); }
private:
    Controller* controller;
}

Почему же был использован в статье косвенный вызов вместо прямого? Может быть этот прием имеет какие-то преимущества? Статья ответа на эти вопросы читателю не дает. Пока мы видим только недостатки такого подхода:
— ошибка вызова несуществующего метода по несуществующему коду обнаружится только во время запуска программы ( в секции default switch'а в контроллере), тогда как прямой вызов несуществующего метода обнаруживается уже на этапе компиляции (а в некоторых редакторах — на этапе написания программы)
— неоправданное усложнение реализации
Но если начать изобретать применение этому подходу, то один плюс у него все-таки есть. Мы можем параметризовать View вызываемой операцией:
enum O { OPCODE1, OPCODE2, OPCODE3 }

class View {
public:
    O code;
    void edit1(P attribute) 
        { controller->execute(code, attribute);    }
private:
    Controller* controller;
}

....
//где-то на этапе инициализации
View* view = new View;
view->code = OPCODE2;
view->setController(controller);
....

В результате View абстрагируется от вызываемой операции, и можно менять поведение экземляров View без переписывания самого класса. Но View все еще зависит от контроллера и может выполнять только операции с одним параметром, поэтому запрос окончательно не инкапсулирован.
Однако в статье такое использование не упоминается, и для читателя применение косвенных вызовов методов контроллера вместо прямых вызовов остается загадкой.

Обратите внимание, что представление и контроллер независимы, несмотря на ограничение по модели.


!true. Как было показано выше, View зависит от контроллера, так как обращается к контроллеру через его открытый интерфейс. Стоит изменить открытый интерфейс — имя кода метода в switch'е метода execute контроллера, либо удалить код, то придется изменять и View. Это ли не зависимость между ними?


2. Реализация истории команд

Во-вторых, продемонстрируем, как легко расширяется функциональность контроллера, который представляет реализацию шаблона проектирования Command – научим контроллер хранить историю изменений и предоставлять возможность последовательно отменять последние произведенные действия.

Как уже было сказано "вызов методов по их коду" можно легко заменить на эквивалентный прямой вызов методов:

class Controller
{
public:
    public void Edit(Model<P> model, P attribute) 
    {
        assert(attribute != null);
        if (!model.getProperty().equals(attribute)) {
            history.push(model.getProperty());
            model.setProperty(attribute);
        }
    }
    public void Undo(Model<P> model, P attribute) 
    {
        assert(attribute != null);
        if (!history.empty()) {
            P property = history.pop();
            if (!model.getProperty().equals(property))
                model.setProperty(property);
        }
    }
private:
    Stack history = new Stack();
}

Почему в статье утверждается, что "легко расширяется функциональность контроллера, который представляет реализацию шаблона проектирования Command", если ту же самую функциональность можно еще легче реализовать прямым вызовом методов контроллера представлением, читателю остается непонятным.


3. В качестве обзора MVC и небольшого экскурса в generic-программирование, статья может быть полезна, но стоит представить использование обобщенного MVC в слегка более сложном приложении, чем в приведенном примере, то возникает множество вопросов, на которые статья не отвечает.

Объекты класса Switch в примере очень простые. Они не обладают поведением, на них не ссылаются другие объекты, и поэтому всю работу с ними можно свести к простой замене одного объекта другим с измененным состоянием, как и делается в примере.
Добавим к Switch поведение. Допустим, наш переключатель символизирует переключатель на каком-то приборе. Переключатель может быть переведен в состояние "включено", только если прибор подключен к электросети, иначе этого сделать нельзя.
Где мы должны реализовать это ограничение? В представлении или контроллере мы этого сделать не можем, потому что тогда подключая к модели другой контроллер и представления, мы должны дублировать код из старых. Реализуя это ограничение непосредственно в модели, мы должны порождать отдельную модель для каждого "свойства модели", отличающегося поведением, и таким образом теряем то, к чему стремились при написании обобщенного MVC — порождения модели автоматически путем передачи параметра "свойство модели", без необходимости писать модель вручную. Значит нам остается только одно — реализовать это поведение непосредственно в "свойстве модели" классе Switch.
class Switch {
public:
        enum State { On, Off };
        Switch(bool Powered) { this->Powered = Powered; }

    void setOn()  
        { if(Powered) state = On; }
    void setOff()  
        { state = Off; }
        State state;
private:
        const bool Powered;
}


Кто будет непосредственно вызывать функции setOn, setOff? Если это будет делать модель, то она должна предоставить контроллеру интерфейс для этого, следовательно мы опять приходим к необходимости написания отдельной модели для каждого "свойства модели", избавляясь от обобщенного подхода. Если это будет делать контроллер, вынимая "свойство модели" через model.getProperty(), то контроллеру нужен способ вызвать обновление всех представлений после выполнения операций над "свойством модели". Как он будет это делать? Ведь метод модели _notifyAll() объявлен как protected, и контроллер не содержит ссылок на представления.
И независимо от того, будет ли вызов методов "свойства модели" производиться в контроллере или модели, перед нами встает дилемма:
обновлять все представления каждый раз после выполнения любого метода "свойства модели", в предположении что state "свойства" изменился, тем самым производя частые холостые обновления, либо
проверять каким-либо способом изменилось ли состояние "свойства", а так как мы не знаем чтО может изменить в "свойстве" его метод, то сделать это можно только копированием всего "свойства" перед вызовом его метода и сравнения его со "свойством" после вызова (а если "свойство" весит 1Гб? а если "свойство" — всего лишь proxy к базе данных?).
Таким образом без поддержки самого "свойства" проверить изменилось ли оно мы не можем. Значит просто так взять любой класс и передать его в обобщенный MVC как параметр "свойство модели" без модификации класса нельзя. В статье этот аспект покрыт мраком.

4.

Модель или оповещает конкретного подписчика методом _notify, или оповещает всех своих подписчиков методом _notifyAll. Оповещение подписчиков осуществляется последовательным оповещением каждого – опять же методом _notifyAll.

Модель никогда не должна оповещать конкретного подписчика. Для нее все подписчики на одно лицо, и оповещать может либо всех, либо ни одного. Если было б иначе, то модель бы зависела от представлений.
В последнем слове цитаты видимо опечатка — должно быть не _notifyAll, а _notify.
Re[8]: Обобщенный Model-View-Controller
От: IB Австрия http://rsdn.ru
Дата: 03.04.07 12:26
Оценка: 6 (1) +1
Здравствуйте, Al_Shargorodsky, Вы писали:

A_S>С одной стороны, действительно, замыкать архитектуру на конкретный фреймворк нехорошо. С другой, при использовании классического MVC/MVP теряются все преимущества WPF и вообще смысл переходить на него с WinForms...

Как это теряются? Ничего не теряется, наоборот, помимо собственно WPF механики получаем почти готовый презентер.

A_S>Т.е. если у меня данные уже отделены от представления на уровне фреймворка, зачем порождать связи Презентер-Представление, имплементировать какой-нибудь IXyzView, вручную его обновлять и т.д.

Связь презентер-представление и так есть, ее можно использовать в своих целях, главное обучить презентер понимать модель.

A_S>Опять-таки, не будучи толком знаком с ASP.NET, решил вникнуть, так сказать, поглубже. Нашел там интересный (опять-таки на мой взгляд новичка) ObjectDataSource контрол, использование которого тоже не сильно вяжется с классическим MVP.

Вот за ObjectDataSource команду asp.Net-а надо к десяти годам изнурительного кодирования приговаривать. Более кривого решения для байндинга я не припомню.
Другое дело, что это имеет довольно мало отношения к MVC.

A_S> Возможно, здесь я и ошибаюсь, просто что я хочу сказать — в каждой из этих конкретных технологий есть свои фишки, дающие определенные преимущества, и хотелось бы эти преимущества использовать максимально.

ODS — даже не стоит упоминания, там не преимущества а сплошное издевательство, а WPF проектировался именно в рассчете на то, что его будут использовать в MVP.

A_S> Отсюда напрашивается вывод — создание какого-то промежуточного слоя между бизнес-логикой и Представлением для адаптации под конкретный фреймворк.

В случае WPF этот слой называется DataModel.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[6]: Обобщенный Model-View-Controller
От: IB Австрия http://rsdn.ru
Дата: 29.03.07 09:29
Оценка: 5 (2)
Здравствуйте, Al_Shargorodsky, Вы писали:

A_S>Т.е. чтобы использовать binding в обе стороны, нужно будет делать либо обертку вокруг модели, либо делать свойства модели виртуальными и плодить наследников?

Не либо. Обертка во круг модели, других вариантов нет.

A_S> Но что мешает сделать несколько DataTemplate и получить несколько Представлений, при этом еще и синхронизированных?

Тем, что это прибъет модель гвоздями к WPF.

A_S>Собственно, я и пытаюсь сказать, что разделение на Модель и Презентер в WPF становится не актуальным — данные уже отделены от Представления средствами фреймворка, а логика реализуется либо во ViewModel, либо в классах-обработчиках команд, либо вообще в отдельных блоках, подписанных на тот же PropertyChanged соответствующего объекта.

Понимаешь, модель может быть представима не только в WPF. Например в моих задачах одну и ту же модель нужно пихать в веб-сервисы, отображать на вебе и WinForms, помимо самого WPF, и еще чего-нибудь хитрое с ней делать. И это скорее правило, нежели исключение.
Поэтому делать из модели WPF-овский презентер — не лучшая идея.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re: Обобщенный Model-View-Controller
От: bolshik Россия http://denis-zhdanov.blogspot.com/
Дата: 23.03.07 10:58
Оценка: 12 (1)
Здравствуйте, Сергей Рогачев, Вы писали:

СР>Статья:

СР>Обобщенный Model-View-Controller
Автор(ы): Сергей Рогачев
Дата: 23.03.2007
В статье рассматривается вариант реализации шаблона проектирования Model-View-Controller в виде каркаса приложения на основе обобщенного программирования языков Java и C#. В описании предлагаемого решения, кроме того, будут рассмотрены шаблоны проектирования Mediator, Observer и Command и показаны варианты их применения в рассматриваемой реализации Model-View-Controller. Предполагается наличие у читателя знания базовых шаблонов проектирования, языка UML, диаграммами которого будут сопровождаться описания, а также одного из указанных языков программирования.


СР>пара комментариев:


1.

...отсутствует четкое разделение между представлением и контроллером, в особенности это касается .NET...

Ну как сказать, Swing вообще работает только с model + UI, где UI = view + controller;

2. Отсутствуют проверки на null принимаемых аргументов и не решена упоминавшаяся проблема с синхронизацией. Причем не только синхронизированный listeners management, но и синхронизированные доступы к свойству
Пример:

public abstract class Model<P> {

    private P property;

    ...

    public Model(P property) {
        this.property = property;
    }

    public P getProperty() {
        return property;
    }

    public void setProperty(P property) {
        this.property = property;
        notifyListeners();
    }
...

Если get() происходит после того, как начался set(), но до того, как он закончился, будут проблемы;

3. finalize() использовать настоятельно не рекомендуется. Почему можно почитать у того же Brian Goetz. Вместо этого используется механизм фантомных ссылок;

4. Для работы с listeners также лучше применять слабые ссылки с целью избежания утечки памяти. Подробнее здесь;

5. Имхо не самая оптимальная работа с дженериками. Я по-быстрому перекидал их:

Model.java
package ru.rsdn.mvc.model;

import java.util.Collection;
import java.util.HashSet;

public abstract class Model<P> {

    private P property;

    private final Collection<IModelSubscriber<P>> subscribers = new HashSet<IModelSubscriber<P>>();

    public Model(P property) {
        this.property = property;
    }

    public P getProperty() {
        return property;
    }

    public void setProperty(P property) {
        this.property = property;
        notifyListeners();
    }

    protected void notifyListeners() {
        for (IModelSubscriber<P> listener : subscribers) {
            notifyListener(listener);
        }
    }

    private void notifyListener(IModelSubscriber<P> subscriber) {
        subscriber.modelChanged(this);
    }

    public void subscribe(IModelSubscriber<P> subscriber) {
        assert !subscribers.contains(subscriber) : "Повторная подписка: "
                + subscriber;
        subscribers.add(subscriber);
        notifyListener(subscriber);
    }

    public void unsubscribe(IModelSubscriber subscriber) {
        assert subscribers.contains(subscriber) : "Неизвестный подписчик: "
                + subscriber;
        subscribers.remove(subscriber);
    }

    public String toString() {
        return property.toString();
    }
}


IModelSubscriber.java
package ru.rsdn.mvc.model;

public interface IModelSubscriber<P> {

    void modelChanged(Model<P> model);
}


ListModel.java
package ru.rsdn.mvc.model;

import java.util.Collection;
import java.util.HashSet;

public class ListModel<P> extends Model<Collection<Model<P>>> implements IModelSubscriber<P> {

    public ListModel() {
        super(new HashSet<Model<P>>());
    }
    
    public void add(Model<P> model) {
        getProperty().add(model);
        model.subscribe(this);
    }


    public void modelChanged(Model<P> model) {
        notifyListeners();
    }

    public void remove(Model<P> model) {
        model.unsubscribe(this);
        getProperty().remove(model);
        notifyListeners();
    }
}


Controller.java
package ru.rsdn.mvc.controller;

import ru.rsdn.mvc.model.Model;

public class Controller<P> implements IController<Controller.Operations, P, Model<P>> {
    
    public enum Operations {EDIT}

    public void execute(Operations operation, Model<P> model, P attribute) {
        assert attribute != null : "Не передан атрибут в операцию";
        switch (operation) {
        case EDIT:
            model.setProperty(attribute);
            break;
        default:
            assert false : "Неизвестная операция: " + operation;
        }
    }
}


IController.java
package ru.rsdn.mvc.controller;

import ru.rsdn.mvc.model.Model;

public interface IController<O, P, M extends Model<P>> {

    void execute(O operation, M model, P attribute);
}


ListController.java
package ru.rsdn.mvc.controller;

import ru.rsdn.mvc.model.ListModel;
import ru.rsdn.mvc.model.Model;

import java.util.Collection;
import java.util.Arrays;

public class ListController<P> implements IController<ListController.Operations, Collection<Model<P>>, ListModel<P>> {

    public enum Operations {ADD, REMOVE}

    public void execute(Operations operation, ListModel<P> listModel, Model<P> attribute) {
        execute(operation, listModel, Arrays.asList(attribute));
    }

    public void execute(Operations operation, ListModel<P> listModel, Collection<Model<P>> attribute) {
        assert attribute != null : "Не передан атрибут в операцию";
        switch (operation) {
            case ADD:
                for (Model<P> model : attribute) {
                    listModel.add(model);
                }
                break;
            case REMOVE:
                for (Model<P> model : attribute) {
                    listModel.remove(model);
                }
                break;
            default:
                assert false : "Неизвестная операция: " + operation;
        }
    }
}


BaseView.java
package ru.rsdn.mvc.view;

import ru.rsdn.mvc.model.IModelSubscriber;
import ru.rsdn.mvc.model.Model;

public abstract class BaseView<P, M extends Model<P>> implements IModelSubscriber<P> {
    private M model;

    protected M getModel() {
        return model;
    }

    public void setModel(M model) {
        unsubscribe();
        this.model = model;
        subscribe();
    }

    private void subscribe() {
        if (model != null) {
            model.subscribe(this);
        }
    }

    private void unsubscribe() {
        if (model != null) {
            model.unsubscribe(this);
        }
    }

    protected void finalize() throws Throwable {
        unsubscribe();
        super.finalize();
    }
}


View.java
package ru.rsdn.mvc.view;

import ru.rsdn.mvc.controller.Controller;
import ru.rsdn.mvc.model.Model;

public abstract class View<P> extends BaseView<P, Model<P>> {

    private final Controller<P> controller = new Controller<P>();

    protected void edit(P property) {
        controller.execute(Controller.Operations.EDIT, getModel(), property);
    }
}


ListView.java
package ru.rsdn.mvc.view;

import ru.rsdn.mvc.controller.Controller;
import ru.rsdn.mvc.controller.ListController;
import ru.rsdn.mvc.model.ListModel;
import ru.rsdn.mvc.model.Model;

import java.util.Collection;

public abstract class ListView<P> extends BaseView<Collection<Model<P>>, ListModel<P>> {

    private final Controller<P> controller = new Controller<P>();
    private final ListController<P> listController = new ListController<P>();

    protected void edit(Model<P> model, P property) {
        controller.execute(Controller.Operations.EDIT, model, property);
    }

    protected void add(Model<P> model) {
        listController.execute(ListController.Operations.ADD, getModel(), model);
    }

    protected void delete(Model<P> model) {
        listController.execute(ListController.Operations.REMOVE, getModel(), model);
    }
}


6. В текущей реализации для выбора нужной операции используется switch. В перспективе это не самое удобное решение (например, будет не две операции, а двадцать две). Лучше сделать через набор обработчиков операций, имеющих общий интерфейс (пока в джаве нет делегатов) и при необходимости обработать команду, брать из map нужный обработчик и делегировать задачу ему;
http://denis-zhdanov.blogspot.com
Re: Обобщенный Model-View-Controller
От: Al_Shargorodsky Украина  
Дата: 23.03.07 07:16
Оценка: 5 (1)
Здравствуйте, Сергей Рогачев, Вы писали:

Возможно, кого-то заинтересует, как архитектура может выглядеть при использовании WPF. Если коротко — контроллер оказывается не нужным в принципе...
Re[2]: Обобщенный Model-View-Controller
От: IB Австрия http://rsdn.ru
Дата: 23.03.07 08:50
Оценка: 5 (1)
Здравствуйте, Al_Shargorodsky, Вы писали:

A_S> Если коротко — контроллер оказывается не нужным в принципе...

Да, там его переименовали в ViewModel... =) Когда контроллер не реализуется в принципе — это паттерн DocumentView. Там логика контроллера реализуется во View, что затрудняет тестирование и обладает рядом других недостатков...

http://rsdn.ru/?article/patterns/ModelViewPresenter.xml
Автор(ы): Иван Бодягин
Дата: 25.07.2006
В наше время сложно найти разработчика, который не слышал бы о паттерне под названием Model-View-Controller или сокращенно MVC, что вообщем не удивительно, с задачей отделения данных от их представления сталкиваешься практически на каждом проекте. Однако, как ни странно, столь же сложно найти разработчика, который действительно четко себе представляет, что такое на самом деле паттерн MVC и как его можно реализовать в конкретной ситуации. Основная причина такой неоднозначности в том, что по историческим причинам данной аббревиатурой принято называть не один единственный паттерн, а целое семейство паттернов, призванное отделять представление от модели. Произошло это в силу разных обстоятельств. Отчасти из-за того что MVC не просто паттерн, а довольно объемное архитектурное решение, в котором каждый новый разработчик видел что-то свое и ставя во главу угла особенности своего проекта, реализовывал его по своему. Отчасти же из-за возраста данного паттерна, во времена его изобретения и сами приложения, и графические интерфейсы были существенно беднее чем в наше время, с тех пор они сильно эволюционировали и вместе с ними изменялся и сам паттерн. Данная статья посвящена также одному из паттернов входящих в это семейство, причинам его появления, особенностям применения, преимуществам и недостаткам, а так же описанию сопутствующих паттернов.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re: Обобщенный Model-View-Controller
От: Дмитрий В  
Дата: 29.03.07 14:45
Оценка: 4 (1)
Здравствуйте, Сергей Рогачев, Вы писали:

СР>Статья:

СР>Обобщенный Model-View-Controller
Автор(ы): Сергей Рогачев
Дата: 23.03.2007
В статье рассматривается вариант реализации шаблона проектирования Model-View-Controller в виде каркаса приложения на основе обобщенного программирования языков Java и C#. В описании предлагаемого решения, кроме того, будут рассмотрены шаблоны проектирования Mediator, Observer и Command и показаны варианты их применения в рассматриваемой реализации Model-View-Controller. Предполагается наличие у читателя знания базовых шаблонов проектирования, языка UML, диаграммами которого будут сопровождаться описания, а также одного из указанных языков программирования.


СР>Авторы:

СР> Сергей Рогачев

СР>Аннотация:

СР>В статье рассматривается реализация шаблона проектирования Model-View-Controller на основе обобщенного программирования языков Java и C#. В описании предлагаемого решения, кроме того, будут рассмотрены шаблоны проектирования Mediator, Observer и Command. Предполагается наличие у читателя знания базовых шаблонов проектирования, языка UML, диаграммами которого будут сопровождаться описания, а также одного из указанных языков программирования.

Честно говоря тема реализации грамотного гуевого фреймворка не раскрыта.
Нуда, есть MVC и все такое, слушатели, подписчики — об этом и так много книг написано.
Только делать слабые связи между обьектами нужно не потому, что об этом написано везде в книжках и что это хорошо, а потому, что это действительно надо.
И с самого начала статьи надо было написать — есть такая то проблема, и она решается так то так. А статья начинается с того, что "В статье рассматривается реализация шаблона проектирования Model-View-Controller" — вот она оказывается какая проблема — хотим MVC использовать, потому что это хорошо.. нде...
Re[5]: Обобщенный Model-View-Controller
От: bolshik Россия http://denis-zhdanov.blogspot.com/
Дата: 26.03.07 09:00
Оценка: +1
Здравствуйте, rsn81, Вы писали:

R>Да, эту статью про неблокирующие алгоритмы CAS уже читал. Вопрос только в том, действительно ли в приложении будет несколько потоков, борющихся за доступ к модели — может чего-то путаю, но вроде SWT и Swing исполняются в одном потоке.


Насчет SWT не знаю, но Swing да, работает в одном потоке, но в то же время никто не запрещает вызвать сеттер модели из другого потока, не EDT. При этом с одной стороны виноват программист, который вызывает его не из EDT, а с другой стороны удобнее использовать класс, просто вызывая сеттер, чем постя обновление через invokeLater(). Т.к. издержки на производительность при этом незначительные (из-за поддержки CAS-инструкций процессором), кажется, что оно того стоит.
http://denis-zhdanov.blogspot.com
Re[2]: Обобщенный Model-View-Controller
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 24.03.07 12:24
Оценка:
Здравствуйте, bolshik, Вы писали:

1. Приводил в свое время пример Swing MVC здесь: Re[8]: вопрос по паттерну MVC
Автор: rsn81
Дата: 19.09.06
, что и было прокомментировано в статье:

контроллер представляет собой набор анонимных классов обработки соответствующих событий


2-5. Ага, так и есть — не хотелось усложнять примеры:

Приводимый код вовсе не является готовым решением. Для наглядности указания направления, в котором, возможно, стоит двигаться, компоненты реального приложения были максимально упрощены, а демонстрационные примеры программ приведены для подтверждения верности выбранного решения.


2. Установить в классе Model cинхронизацию по property в методе setProperty, но, по-моему, смысла в этом мало.
3. Да. Но в данном случае это не страшно: методы finalize используются в классах представлений, которые создаются-собираются не так часто.
4. Спасибо, надо изучить на досуге.
5. Супер, большое спасибо за рефакторинг! Именно так и пытался сделать вначале, но камнем преткновения становился ListController (и ListView), в котором вы предложили такой "финт ушами" сделать, до которого сам не смог додуматься.

Обновил исходный код: http://rsdn.ru/File/57445/mvc-rsdn_1.5-java-src.zip
Изменения в версии 1.5:
1. Изменена работа с generic-ами по варианту bolshik-а.
2. Список подписчиков модели в классе Model<P> на основе класса CopyOnWriteArrayList (ранее на HashSet), по рекомендации Браяна Гетца http://www.ibm.com/developerworks/ru/library/j-jtp07265/index.html

PS Статье на самом деле уже больше полугода — Java-код статьи выдирался из рабочих проектов в августе-сентябре 2006 года. Код серьезно уже давно не смотрел, т.к., в принципе, по работе уже отошел от MVC: после статьи IB Model-View-Controller в .Net
Автор(ы): Иван Бодягин
Дата: 25.07.2006
В наше время сложно найти разработчика, который не слышал бы о паттерне под названием Model-View-Controller или сокращенно MVC, что вообщем не удивительно, с задачей отделения данных от их представления сталкиваешься практически на каждом проекте. Однако, как ни странно, столь же сложно найти разработчика, который действительно четко себе представляет, что такое на самом деле паттерн MVC и как его можно реализовать в конкретной ситуации. Основная причина такой неоднозначности в том, что по историческим причинам данной аббревиатурой принято называть не один единственный паттерн, а целое семейство паттернов, призванное отделять представление от модели. Произошло это в силу разных обстоятельств. Отчасти из-за того что MVC не просто паттерн, а довольно объемное архитектурное решение, в котором каждый новый разработчик видел что-то свое и ставя во главу угла особенности своего проекта, реализовывал его по своему. Отчасти же из-за возраста данного паттерна, во времена его изобретения и сами приложения, и графические интерфейсы были существенно беднее чем в наше время, с тех пор они сильно эволюционировали и вместе с ними изменялся и сам паттерн. Данная статья посвящена также одному из паттернов входящих в это семейство, причинам его появления, особенностям применения, преимуществам и недостаткам, а так же описанию сопутствующих паттернов.
, а конкретно про модификацию MVC — Model-View-Presenter — успешно переполз на него и радуюсь пассивной модели.
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[3]: Обобщенный Model-View-Controller
От: Al_Shargorodsky Украина  
Дата: 26.03.07 05:56
Оценка:
Здравствуйте, IB, Вы писали:

IB>Да, там его переименовали в ViewModel... =) Когда контроллер не реализуется в принципе — это паттерн DocumentView. Там логика контроллера реализуется во View, что затрудняет тестирование и обладает рядом других недостатков...


Всетаки ViewModel это не совсем контроллер-презентер. Я бы сказал так — ViewModel можно привести к виду презентера, но это только частный случай. Модифицируем тот же пример
Автор(ы): Иван Бодягин
Дата: 25.07.2006
В наше время сложно найти разработчика, который не слышал бы о паттерне под названием Model-View-Controller или сокращенно MVC, что вообщем не удивительно, с задачей отделения данных от их представления сталкиваешься практически на каждом проекте. Однако, как ни странно, столь же сложно найти разработчика, который действительно четко себе представляет, что такое на самом деле паттерн MVC и как его можно реализовать в конкретной ситуации. Основная причина такой неоднозначности в том, что по историческим причинам данной аббревиатурой принято называть не один единственный паттерн, а целое семейство паттернов, призванное отделять представление от модели. Произошло это в силу разных обстоятельств. Отчасти из-за того что MVC не просто паттерн, а довольно объемное архитектурное решение, в котором каждый новый разработчик видел что-то свое и ставя во главу угла особенности своего проекта, реализовывал его по своему. Отчасти же из-за возраста данного паттерна, во времена его изобретения и сами приложения, и графические интерфейсы были существенно беднее чем в наше время, с тех пор они сильно эволюционировали и вместе с ними изменялся и сам паттерн. Данная статья посвящена также одному из паттернов входящих в это семейство, причинам его появления, особенностям применения, преимуществам и недостаткам, а так же описанию сопутствующих паттернов.
.
   public class Model : INotifyPropertyChanged
   {
      private double _valueFahrenheit = 32;
      private double _valueCelsius = 0;

      public event PropertyChangedEventHandler PropertyChanged;

      public double valueFahrenheit
      {
         get { return _valueFahrenheit; }
         set 
            { 
            _valueFahrenheit = value;
            _valueCelsius = (_valueFahrenheit - 32) * 5 / 9;
            NotifyPropertyChanged("valueFahrenheit");
         }
      }

      public double valueCelsius
      {
         get { return _valueCelsius; }
         set 
         { 
            _valueCelsius = value;
            _valueFahrenheit = _valueCelsius * 9 / 5 + 32;
            NotifyPropertyChanged("valueCelsius");
         }
      }

      private void NotifyPropertyChanged(String info)
      {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
      }
   }

где-то в XAML
<DataTemplate DataType=src:Model>
  <TextBlock Text={Binding valueFahrenheit}/>
  ... и так далее
</DataTemplate>


Больше не нужно ничего — всю черновую работу сделает фреймворк. Класс Model здесь — это и ViewModel и DataModel одновременно. Пример, конечно примитивный, но думаю, суть понятна.
Re[3]: Обобщенный Model-View-Controller
От: bolshik Россия http://denis-zhdanov.blogspot.com/
Дата: 26.03.07 06:46
Оценка:
Здравствуйте, rsn81, Вы писали:

R>...


R>2. Установить в классе Model cинхронизацию по property в методе setProperty, но, по-моему, смысла в этом мало.


Не, смысл-то есть, единственно что эффективнее будет работать не через старые примитивы синхронизации (использование synchronized), а через AtomicReference. Почему это эффективнее, и вообще о CAS-инструкциях можно почитать у того же Brian Goetz


R>3. Да. Но в данном случае это не страшно: методы finalize используются в классах представлений, которые создаются-собираются не так часто.


Спорить не буду, потому что тут, имхо, уже дело субъективное. Я бы либо не использовал finalize() в примере вообще, либо делал на фантомных ссылках, но хозяин барин


R>5. Супер, большое спасибо за рефакторинг! Именно так и пытался сделать вначале, но камнем преткновения становился ListController (и ListView), в котором вы предложили такой "финт ушами" сделать, до которого сам не смог додуматься.


Welcome
http://denis-zhdanov.blogspot.com
Re[4]: Обобщенный Model-View-Controller
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 26.03.07 08:20
Оценка:
Здравствуйте, bolshik, Вы писали:

B>Не, смысл-то есть, единственно что эффективнее будет работать не через старые примитивы синхронизации (использование synchronized), а через AtomicReference. Почему это эффективнее, и вообще о CAS-инструкциях можно почитать у того же Brian Goetz

Да, эту статью про неблокирующие алгоритмы CAS уже читал. Вопрос только в том, действительно ли в приложении будет несколько потоков, борющихся за доступ к модели — может чего-то путаю, но вроде SWT и Swing исполняются в одном потоке.
Re[4]: Обобщенный Model-View-Controller
От: IB Австрия http://rsdn.ru
Дата: 26.03.07 08:33
Оценка:
Здравствуйте, Al_Shargorodsky, Вы писали:

A_S>Всетаки ViewModel это не совсем контроллер-презентер.

Да, не совсем — это только часть контроллера.

A_S> Я бы сказал так — ViewModel можно привести к виду презентера, но это только частный случай.

Не совсем так.
В MVP Presenter (контроллер) выполняет, с одной стороны роль медиатора для модели, а с другой управляет набором View.
В случае WPF ребята эти две роли разделили, в результате Presenter распался на две части: DataModel — медиатор между моделью и View, ModelView — управляет View. Модель же и View остались неизменными. Таким образом, паттерн распался на 4 компонента — Model, DataModel, ModelView и View.
Они сами об этом и пишут: "DataModel is responsible for exposing data in a way that is easily consumable by WPF. All of its public APIs must be called on the UI thread only" Иными словами, роль DataModel в том, чтобы представить данные(Model) в том виде, в котором они удобны для WPF, то есть классическое применение паттерна медиатор.
Касательно ViewModel — "A ViewModel is a model for a view in the application (duh!). It exposes data relevant to the view and exposes the behaviors for the views, usually with Commands"

A_S> public class Model : INotifyPropertyChanged

Если Model — это по прежнему модель, то так делать нельзя. Модель по определению ничего не знает о контроллере и его интерфейсах, а INotifyPropertyChanged — это именно интерфейс контроллера, точнее медиатора для View, а не модели. А у одной модели может быть несколько Презентеров.

A_S> Класс Model здесь — это и ViewModel и DataModel одновременно.

Тогда Model переходит в разряд презентеров.
... << RSDN@Home 1.2.0 alpha rev. 673>>
Мы уже победили, просто это еще не так заметно...
Re[6]: Обобщенный Model-View-Controller
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 26.03.07 16:08
Оценка:
Здравствуйте, bolshik, Вы писали:

Статья обновлена до версии 2.5 с учетом ваших замечаний, еще раз спасибо.
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[3]: Обобщенный Model-View-Controller
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 26.03.07 17:10
Оценка:
Здравствуйте, rsn81, Вы писали:

R>Model-View-Presenter — успешно переполз на него и радуюсь пассивной модели.

Если интересно, то вот демонстрационный пример Generic MVP — все интересное, что описано в разделе статьи "Внедрение", перенесено и в MVP: Undo/Redo (полная поддержка) и клонирование.
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[5]: Обобщенный Model-View-Controller
От: Al_Shargorodsky Украина  
Дата: 29.03.07 05:07
Оценка:
Здравствуйте, IB, Вы писали:

Пару дней пересматривал архитектуру своего текущего проекта и собственные представления в этой области. Пока остался при своем мнении... Буду признателен за дальнейшие разъяснения

A_S>> public class Model : INotifyPropertyChanged

IB>Если Model — это по прежнему модель, то так делать нельзя. Модель по определению ничего не знает о контроллере и его интерфейсах, а INotifyPropertyChanged — это именно интерфейс контроллера, точнее медиатора для View, а не модели. А у одной модели может быть несколько Презентеров.
Т.е. чтобы использовать binding в обе стороны, нужно будет делать либо обертку вокруг модели, либо делать свойства модели виртуальными и плодить наследников? Но что мешает сделать несколько DataTemplate и получить несколько Представлений, при этом еще и синхронизированных?

A_S>> Класс Model здесь — это и ViewModel и DataModel одновременно.

IB>Тогда Model переходит в разряд презентеров.
Собственно, я и пытаюсь сказать, что разделение на Модель и Презентер в WPF становится не актуальным — данные уже отделены от Представления средствами фреймворка, а логика реализуется либо во ViewModel, либо в классах-обработчиках команд, либо вообще в отдельных блоках, подписанных на тот же PropertyChanged соответствующего объекта.
Re: Обобщенный Model-View-Controller
От: Аноним  
Дата: 29.03.07 10:34
Оценка:
Как посмотреть код исходников для ASP.NET?
Re[2]: Обобщенный Model-View-Controller
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 29.03.07 10:36
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Как посмотреть код исходников для ASP.NET?

http://rsdn.ru/article/patterns/generic-mvc.xml#EDBBG
Автор(ы): Сергей Рогачев
Дата: 23.03.2007
В статье рассматривается вариант реализации шаблона проектирования Model-View-Controller в виде каркаса приложения на основе обобщенного программирования языков Java и C#. В описании предлагаемого решения, кроме того, будут рассмотрены шаблоны проектирования Mediator, Observer и Command и показаны варианты их применения в рассматриваемой реализации Model-View-Controller. Предполагается наличие у читателя знания базовых шаблонов проектирования, языка UML, диаграммами которого будут сопровождаться описания, а также одного из указанных языков программирования.
Re[7]: Обобщенный Model-View-Controller
От: Al_Shargorodsky Украина  
Дата: 29.03.07 15:18
Оценка:
Здравствуйте, IB, Вы писали:

IB>Понимаешь, модель может быть представима не только в WPF. Например в моих задачах одну и ту же модель нужно пихать в веб-сервисы, отображать на вебе и WinForms, помимо самого WPF, и еще чего-нибудь хитрое с ней делать. И это скорее правило, нежели исключение.

IB>Поэтому делать из модели WPF-овский презентер — не лучшая идея.

Спасибо, вобщем я где-то так и думал. И все-таки — настолько ли сильно реализация INotifyPropertyChanged привязывает к определенному Представлению? Это ведь просто событие — не хочешь, не подписывайся...
Re[2]: Обобщенный Model-View-Controller
От: Дмитрий В  
Дата: 29.03.07 17:06
Оценка:
В том же Swing'e жавовском MVC в каждом визуальном компоненте — даже у кнопки есть ButtonModel (не говоря уже о таблице), есть контроллер (сам обьект кнопки JButton) и view — ButtonUI. И там как раз JButton подписывается на события изменения модели и вся остальная приблуда тоже присутствует.
Re[3]: Обобщенный Model-View-Controller
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 29.03.07 17:59
Оценка:
Здравствуйте, Дмитрий В, Вы писали:

Что и было отмечено в разделе 1.1:

Java Swing, в отличие от других платформ, не только предоставляет интерфейс разработки на основе шаблона MVC, но и сам реализован на его основе. Представлением является класс – наследник класса Frame. Вследствие организации событийной модели Java на интерфейсах, контроллер представляет собой набор анонимных классов обработки соответствующих событий. Как и остальные платформы, Swing предоставляет разработку модели программисту.


Но, что очень важно в этом отношении, ниже в разделе 1.3 дается такой комментарий:

Помимо реализации MVC на уровне языков программирования, существует достаточно много программных платформ, которые предлагают готовые решения на основе данного шаблона, например, Spring Framework.

СОВЕТ
Следует четко разделять MVC компонентного уровня, по-другому – framework, и уровня приложения. К примеру, Swing является решением идеи MVC на компонентном уровне. Но при проектировании приложения на основе Swing можно также воспользоваться преимуществами MVC, выделив бизнес-логику приложения в модель, и построив представление и контроллер на основе соответствующих классов Swing.

В данной статье рассматривается реализация библиотеки классов, использование которой упростит следование шаблону проектирования MVC на уровне приложений.


Используемая терминология была взята из множества статьей и описаний курсов обучения шаблону MVC, к примеру, вот здесь Component- vs. Application-level MVC Architecture:

Swing adopts MVC at component level. We use it as a case study toillustrate features of MVC and also help students learn to use the tool for programming projects. To encourage them to use beyound a specific tool, we assign students a project to build a domain-specific framework for GUI applications using MVC at application level.

Именно эту мысль и озвучил в статье.
... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[3]: Обобщенный Model-View-Controller
От: Blazkowicz Россия  
Дата: 30.03.07 13:23
Оценка:
Здравствуйте, Дмитрий В, Вы писали:

ДВ>В том же Swing'e жавовском MVC в каждом визуальном компоненте — даже у кнопки есть ButtonModel (не говоря уже о таблице), есть контроллер (сам обьект кнопки JButton) и view — ButtonUI. И там как раз JButton подписывается на события изменения модели и вся остальная приблуда тоже присутствует.


Как оказалось
Автор: Blazkowicz
Дата: 18.09.06
, Swing это все же не совсем MVC.
Re[4]: Обобщенный Model-View-Controller
От: Дмитрий В  
Дата: 30.03.07 14:48
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

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


ДВ>>В том же Swing'e жавовском MVC в каждом визуальном компоненте — даже у кнопки есть ButtonModel (не говоря уже о таблице), есть контроллер (сам обьект кнопки JButton) и view — ButtonUI. И там как раз JButton подписывается на события изменения модели и вся остальная приблуда тоже присутствует.


B>Как оказалось
Автор: Blazkowicz
Дата: 18.09.06
, Swing это все же не совсем MVC.

Да и значит хрен с ним, с этим MVС
Re[7]: Обобщенный Model-View-Controller
От: Al_Shargorodsky Украина  
Дата: 03.04.07 05:24
Оценка:
Здравствуйте, IB, Вы писали:

Таки не дает мне покоя эта тема
С одной стороны, действительно, замыкать архитектуру на конкретный фреймворк нехорошо. С другой, при использовании классического MVC/MVP теряются все преимущества WPF и вообще смысл переходить на него с WinForms... Т.е. если у меня данные уже отделены от представления на уровне фреймворка, зачем порождать связи Презентер-Представление, имплементировать какой-нибудь IXyzView, вручную его обновлять и т.д.
Опять-таки, не будучи толком знаком с ASP.NET, решил вникнуть, так сказать, поглубже. Нашел там интересный (опять-таки на мой взгляд новичка) ObjectDataSource контрол, использование которого тоже не сильно вяжется с классическим MVP. Возможно, здесь я и ошибаюсь, просто что я хочу сказать — в каждой из этих конкретных технологий есть свои фишки, дающие определенные преимущества, и хотелось бы эти преимущества использовать максимально. Отсюда напрашивается вывод — создание какого-то промежуточного слоя между бизнес-логикой и Представлением для адаптации под конкретный фреймворк. Хотелось бы услышать мнение по этому поводу (просто пока еще есть возможность внести изменения в свой проект...) А может, есть какие-то ссылки на конкретные решения... Заранее спасибо.
Re[9]: Обобщенный Model-View-Controller
От: Al_Shargorodsky Украина  
Дата: 03.04.07 13:09
Оценка:
Здравствуйте, IB, Вы писали:

A_S>>С одной стороны, действительно, замыкать архитектуру на конкретный фреймворк нехорошо. С другой, при использовании классического MVC/MVP теряются все преимущества WPF и вообще смысл переходить на него с WinForms...

IB>Как это теряются? Ничего не теряется, наоборот, помимо собственно WPF механики получаем почти готовый презентер.
Т.е. правильно ли я понимаю? Пусть есть некий MasterObject, содержащий DetailObject и для интереса отдельный SimpleObject. Что я делаю сейчас: созадю MasterView, у которого есть свойство типа MasterObject и, допустим, свойство типа какого-то SimpleView, который содержит SimpleObject (но ведь можно и прямо SimpleObject). Все остальное — в XAMLе.
Чтобы реализовать MVP, между, допустим MasterView и MasterObject нужно вставить MasterPresenter? Или же MasterView унаследовать от, скажем, Window, а SimpleView — от Control? Но в последнем случае как раз и теряется вся прелесть DataTemplate...

IB>ODS — даже не стоит упоминания, там не преимущества а сплошное издевательство, а WPF проектировался именно в рассчете на то, что его будут использовать в MVP.

Тут не силен — просто не довелось пока...

A_S>> Отсюда напрашивается вывод — создание какого-то промежуточного слоя между бизнес-логикой и Представлением для адаптации под конкретный фреймворк.

IB>В случае WPF этот слой называется DataModel.
Это если принять выше первый вариант?

Спасибо за разъяснения
Re[4]: Обобщенный Model-View-Controller
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 05.04.07 15:45
Оценка:
Здравствуйте, Blazkowicz, Вы писали:

B>Как оказалось
Автор: Blazkowicz
Дата: 18.09.06
, Swing это все же не совсем MVC.

И они достаточно четко говорят о расхождениях. Вы видите в этом что-то нехорошее?

Root in MVC

The first Swing prototype followed a traditional MVC separation in which each component had a separate model object and delegated its look-and-feel implementation to separate view and controller objects.

To MVC or not to MVC?

So Swing does have a strong MVC lineage. But it's also important to reiterate that our MVC architecture serves two distinct purposes:

— First, separating the model definition from a component facilitates model-driven programming in Swing.
— Second, the ability to delegate some of a component's view/controller responsibilities to separate look-and-feel objects provides the basis for Swing's pluggable look-and-feel architecture.

... << RSDN@Home 1.2.0 alpha rev. 676>>
Re[5]: Обобщенный Model-View-Controller
От: denis miller Россия http://agile20.ru
Дата: 05.04.07 17:55
Оценка:
http://martinfowler.com/eaaDev/uiArchs.html
Re[2]: Обобщенный Model-View-Controller
От: rsn81 Россия http://rsn81.wordpress.com
Дата: 24.06.07 12:06
Оценка:
Здравствуйте, ALSK, Вы писали:

Спасибо за такой развернутый анализ!

1-2. Критика реализации Command верная. Чуть выше bolshik уже намекал на это же: конкретные действия над получателем в статье инкапсулированы в контроллер (клиент), в то время как в теории это должно производится в конкретной команде, а клиент должен только получать команду и устанавливать получателя (модель). Как вариант, можно, к примеру, сделать следующий рефакторинг:

package com.rogachev.patterns.behavioral.command;

public enum COMMAND {
    COMMAND1() {
        @Override
        public void execute(Receiver receiver) {
            ...
        }
    },
    COMMAND2() {
        @Override
        public void execute(Receiver receiver) {
            ...
        }
    };
    public abstract void execute(Receiver receiver);
}

Теперь потребность в блоке switch в контроллере отпадает, т.е. контроллер уже не зависит от набора команд. Ньюанс в том, что в отличие от Java, C#-перечисления сделать подобное не позволят — как вариант, вообще отказаться от перечислений и использовать обычные классы.

3. Как вариант, можно поступать следующим образом... Класс свойства модели должен реализовать интерфейс копирования (не клонирования):

package com.rogachev.patterns.clone;

public interface IDuplicable<T extends IDuplicable<T>> {
    void duplicate(T obj) throws ...;
}

Теперь модель изменяет свойство следующим образом:

package com.rogachev.patterns.mvc.model;

import java.util.Collection;
import java.util.concurrent.CopyOnWriteArrayList;

public class Model<P> {
    ...
    public void setProperty(P _property) {
        assert _property != null;
        // property = _property;
        try {
            property.duplicate(_property);
            _notifyAll();
        } catch (... e) {
        }
    }
    ...
}

Ну, а собственно ограничение вы описываете в свойстве модели, как и вы решили — в методе интерфейса IDuplicable. В итоге объект свойства модели становится persistence, что упрощает работу с некоторыми библиотеками т.н. DAL Persistence objects, вроде db4o.

4.
ALS>Модель никогда не должна оповещать конкретного подписчика.
Издатель (модель) может оповестить конкретного подписчика (представление или модель списка), это упрощает инициализацию представлений по умолчанию:

Подписчики регистрируются в модели методом subscribe. Регистрация сводится к добавлению подписчика в список subscribers и принудительному его оповещению – вызов метода _notify. Таким образом, после регистрации в качестве подписчика модели представление сразу же получает оповещение и впервые отображает модель.


ALS>В последнем слове цитаты видимо опечатка — должно быть не _notifyAll, а _notify.

Видимо просто несколько сумбурно сказано. Имелось в виду, что оповещение подписчиков производится в методе _notifyAll посредством последовательного вызова метода _notify у каждого подписчика.
Re[3]: Обобщенный Model-View-Controller
От: ALSK  
Дата: 25.06.07 10:10
Оценка:
Здравствуйте, rsn81, Вы писали:

R>3. Как вариант, можно поступать следующим образом... Класс свойства модели должен реализовать интерфейс копирования (не клонирования):


R>
package com.rogachev.patterns.clone;

R>public interface IDuplicable<T extends IDuplicable<T>> {
R>    void duplicate(T obj) throws ...;
R>}

R>Теперь модель изменяет свойство следующим образом:

R>
package com.rogachev.patterns.mvc.model;

R>import java.util.Collection;
R>import java.util.concurrent.CopyOnWriteArrayList;

R>public class Model<P> {
R>    ...
R>    public void setProperty(P _property) {
R>        assert _property != null;
R>        // property = _property;
R>        try {
R>            property.duplicate(_property);
R>            _notifyAll();
R>        } catch (... e) {
R>        }
R>    }
R>    ...
R>}

R>Ну, а собственно ограничение вы описываете в свойстве модели, как и вы решили — в методе интерфейса IDuplicable. В итоге объект свойства модели становится persistence, что упрощает работу с некоторыми библиотеками т.н. DAL Persistence objects, вроде db4o.

Для простых свойств (например для базовых типов) возможно это будет работать отлично, но если "свойство модели" громоздко, содержит кучу аттрибутов, то такое решение будет страшно непроизводительным. Ведь мы должны перебрать и скопировать все аттрибуты, даже если операция пользователя привела к изменению только какого-то одного аттрибута. Причем такой полный перебор аттрибутов происходит дважды: в equals в контроллере, и в duplicate в модели.
Вообще я бы разделил для такого MVC типы объектов на два вида: простые (без поведения, легковесные, нельзя иметь ссылку на такой объект) и сложные (без ограничений). Простые можно смело оборачивать в "модель" и общаться с ними таким незамысловатым образом как двумя операциями equals и duplicate, а со сложными обращаться каким-то другим механизмом.

R>4.

R>Издатель (модель) может оповестить конкретного подписчика (представление или модель списка), это упрощает инициализацию представлений по умолчанию:
R>

Подписчики регистрируются в модели методом subscribe. Регистрация сводится к добавлению подписчика в список subscribers и принудительному его оповещению – вызов метода _notify. Таким образом, после регистрации в качестве подписчика модели представление сразу же получает оповещение и впервые отображает модель.


При таком подходе, верно. Это я упустил.
Просто в моей реализации MVC представление может быть подписано на модель до того, как будет полностью проинициализировано и сконфигурировано. Например, в конструкторе базового класса, или до передачи "целевого" контрола в представление. Таким образом вызов notify для такого представления во время подписки приведет к ошибке. Выглядит конечно не очень безопасно (вдруг модель вызовет обновление подписчиков раньше чем нужно), но зато избавляет разработчика от необходимости обеспечивать подписку строго после полного "укомплектования" представления.
Re: Обобщенный Model-View-Controller
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 05.02.08 04:15
Оценка:
СР>Статья:
СР>Обобщенный Model-View-Controller
Автор(ы): Сергей Рогачев
Дата: 23.03.2007
В статье рассматривается вариант реализации шаблона проектирования Model-View-Controller в виде каркаса приложения на основе обобщенного программирования языков Java и C#. В описании предлагаемого решения, кроме того, будут рассмотрены шаблоны проектирования Mediator, Observer и Command и показаны варианты их применения в рассматриваемой реализации Model-View-Controller. Предполагается наличие у читателя знания базовых шаблонов проектирования, языка UML, диаграммами которого будут сопровождаться описания, а также одного из указанных языков программирования.


выложена обновленная версия — 3.0
... << RSDN@Home 1.2.0 alpha rev. 786>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.