Является ли Ext JS MVC анти-шаблоном?

Я работаю в команде из 25 разработчиков. Мы используем шаблон ExtJS MVC для Sencha. Но мы считаем, что их определение MVC вводит в заблуждение. Возможно, мы могли бы также называть их MVC анти-шаблоном.

AMAIK, в контроллере MVC знает только имя или путь представления и не знает о внутренней структуре представления. Например, это не ответственность диспетчера, независимо от того, отображает ли список клиентов простое раскрытие или автозаполнение.

Однако в Ext JS MVC контроллер должен знать рендеринг элементов вида, поскольку контроллер подключается к этим элементам и прослушивает их события. Это означает, что если элемент представления изменяется (например, кнопка становится ссылкой), то соответствующий селектор в контроллере тоже должен измениться. Другими словами, контроллер тесно связан с внутренней структурой представления.

Является ли эта причина приемлемой для денонсирования Ext JS MVC как анти-шаблона? Правильны ли мы, что контроллеры связаны с представлениями?

Ответ 1

ОБНОВЛЕНИЕ (март 2015 г.): Внедрение 5.0 внесло ViewControllers, в котором должны быть рассмотрены большинство проблем, обсуждаемых в этот поток. Преимущества:

  • Улучшенная/принудительная область вокруг ссылок компонентов внутри ViewController
  • Легче инкапсулировать специфическую для просмотра логику отдельно от логики управления потоком приложений
  • Жизненный цикл ViewController, управляемый инфраструктурой, вместе с представлением, связанным с

Ext 5 по-прежнему предлагает существующий класс Ext.app.Controller, чтобы поддерживать совместимость в обратном направлении и предоставлять больше гибкости для структурирования вашего приложения.

Оригинальный ответ:

в Ext JS MVC, контроллер должен знать рендеринг элементов вида, потому что контроллер подключается к этим элементам и слушает их события. Это означает, что если элемент представления изменяется (например, кнопка становится ссылкой), то соответствующий селектор в контроллере тоже должен измениться. Другими словами, контроллер тесно связан с внутренней структурой представления.

Я действительно согласен с тем, что в большинстве случаев это не лучший выбор для точных причин, по которым вы цитируете, и, к сожалению, большинство примеров, которые поставляются с Ext и Touch, демонстрируют функции ref и control, которые часто определяются с помощью селекторов, которые нарушают просмотреть инкапсуляцию. Однако это не требование MVC - это то, как были реализованы примеры, и их легко избежать.

Кстати, я думаю, что определенно может иметь смысл различать типы контроллеров между настоящими приложениями контроллерами (контроль потока приложений и общей бизнес-логики, должен быть полностью отключен от представлений) - вот что вы ссылаясь на) и просмотр контроллеров (логика управления/событий, специфичная для представления, тесно связанная с дизайном). Примером последнего может быть логика для координации между виджетами внутри представления, полностью внутри этого представления. Это общий прецедент, и соединение контроллера вида с его представлением не является проблемой - это просто стратегия управления кодами, чтобы держать класс представления как можно глубже.

Проблема заключается в том, что в большинстве документированных примеров каждый контроллер просто ссылается на то, что хочет, и что это не большой шаблон. Однако это НЕ требование реализации Ext MVC - это просто (ленивое?) Соглашение, используемое в их примерах. Это довольно просто (и я бы советовал целесообразно) вместо этого, чтобы ваши классы просмотров определяли собственные пользовательские геттеры и события для чего-либо, что должно быть доступно для контроллеров приложений. Конфигурация refs является просто сокращением - вы всегда можете вызвать что-то вроде myView.getSomeReference() самостоятельно и разрешить виду диктовать то, что возвращается. Вместо this.control('some > view > widget') просто определите настраиваемое событие в представлении и сделайте this.control('myevent'), когда этот виджет сделает то, о чем должен знать контроллер. Легко, как это.

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

Итак, да, привязка контроллеров уровня приложения к внутренним элементам управления представлением сама по себе является анти-шаблоном. Но Ext MVC не требует этого, и очень просто не делать этого самостоятельно.

Ответ 2

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

например: прослушать нажатие этой кнопки или изменить этот элемент или на этот пользовательский компонент/событие.

Целью MVC является развязка компонентов и возможность повторного использования, а Sencha MVC для этого потрясающе. Как говорит @bmoeskau, вы должны быть осторожны в разделении контроллеров представлений (встроенных для самого вида/виджетов) и контроллеров приложений (манипуляций верхнего уровня), чтобы в полной мере использовать шаблон MVC. И это не очевидно, когда вы читаете http://docs.sencha.com/ext-js/4-1/#!/guide/application_architecture. Рефакторируйте свой подход MVC, создайте разные контроллеры, создайте пользовательский компонент и охватите полную архитектуру ExtJS MVC, чтобы воспользоваться им.

По-прежнему существует небольшая проблема в подходе Sencha IMHO, система MVC refs действительно не работает, когда у вас есть несколько экземпляров одних и тех же представлений в приложении. например: если у вас есть TabPanel с несколькими экземплярами одного и того же компонента, система refs нарушена, так как она всегда будет нацелена на первый элемент, найденный в DOM... Существуют обходные пути и проект, пытающийся исправить это, но я надеюсь, что это будет скоро адресовано.

Ответ 3

Я думаю, если вы используете Sencha Architect для создания представлений, то наследуйте от этого представления, чтобы создать свой собственный вид. Теперь этот вид может быть ответственным за подключение к любым событиям и создание значимых событий.

Это просто мысль...

//Designer Generated
Ext.define('MyApp.view.MainView', {
    extend: 'Ext.grid.GridPanel',
    alias: 'widget.mainview',    
    initComponent: function() {
    }
});


//Your View Decorator
Ext.define('MyApp.view.MainView', {
    extend: 'MyApp.view.MainViewEx',
    alias: 'widget.mainviewex',    
    initComponent: function() {
    this.mon(this, 'rowselect', function(){
        this.fireEvent('userselected', arguments);
    }, this);
    }
});

Ответ 4

В настоящее время я перехожу на Fast Track в ExtJS 4 из Sencha Training. У меня большой опыт работы в ExtJS (с ExtJS 2.0), и мне было очень интересно узнать, как MVC был реализован в ExtJS 4.

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

Ext.ns('Test');

Test.MainPanel = Ext.extend(Ext.Container, {
    initComponent : function() {
        this.panel1 = new Test.Panel1({
            listeners: {
                firstButtonPressed: function(){
                    this.panel2.addSomething();
                },
                scope: this
            }
        });
        this.panel2 = new Test.Panel2();

        this.items = [this.panel1,this.panel2];

        Test.MainPanel.superclass.initComponent.call(this);
    }

});

Test.Panel1 = Ext.extend(Ext.Panel, {
    initComponent : function() {
        this.addEvents('firstButtonPressed');

        this.tbar = new Ext.Toolbar({
           items: [{
             text: 'First Button',
               handler: function(){
                   this.fireEvent('firstButtonPressed');
               }
           }] 
        });

        Text.Panel1.superclass.initComponent.call(this);
    }
});

Test.Panel2 = Ext.extend(Ext.Panel, {
    initComponent : function() {
        this.items = [new Ext.form.Label('test Label')]

        Test.Panel2.superclass.initComponent.call(this);
    },

    addSomething: function(){
        alert('add something reached')
    }
});

Как вы можете видеть, моя MainPanel (помимо того, что удерживает обе панели) также делегирует события и тем самым создает связь между этими двумя компонентами, поэтому имитирует тип контроллера.

В ExtJS 4 в нем реализован MVC. Что меня действительно задело, так это то, что контроллер на самом деле извлекает компоненты через QuerySelector, который, на мой взгляд, очень подвержен ошибкам. Давайте посмотрим:

Ext.define('MyApp.controller.Earmarks', {
    extend:'Ext.app.Controller',
    views:['earmark.Chart'],


    init:function () {
        this.control({
             'earmarkchart > toolbar > button':{
                click:this.onChartSelect
            },
            'earmarkchart tool[type=gear]':{
                click:this.selectChart
             }
        });
    }
});

Итак, как мы можем видеть здесь, способ, которым контроллер знает о кнопке и инструменте эрдарного канала, - это селектор. Представьте себе, что я меняю макет в своем earmarkchart, и я фактически перемещаю кнопку за пределами панели инструментов. Внезапно мое приложение разбито, потому что мне всегда нужно знать, что изменение макета может повлиять на связанный с ним контроллер.

Можно сказать, что я могу вместо этого использовать itemId, но снова мне нужно знать, удалю ли я компонент, который мне нужно разбросать, чтобы найти, есть ли какая-либо скрытая ссылка в моих контроллерах для этого itemId, а также факт что у меня не может быть одного элемента itemId для одного родительского компонента, поэтому, если у меня есть itemId, называемый "testId" в Panel1 и тот же в Grid1, тогда мне все равно нужно будет выбрать, хочу ли я itemId из Panel1 или из Grid1.

Я понимаю, что Query очень мощный, потому что он дает вам большую гибкость, но эта гибкость приходит по очень высокой цене, на мой взгляд, и если у меня есть команда из 5 человек, разрабатывающих пользовательские интерфейсы, и мне нужно объяснить эти понятия я подниму руки на огонь, что они сделают множество ошибок из-за пунктов, на которые я ссылался раньше.

Каково ваше общее мнение по этому поводу? Было бы проще просто как-то общаться с событиями? Смысл, если мой Контроллер действительно знает, какие взгляды он ожидает событиями, тогда можно просто запустить событие dosomethingController, а связанный с ним Контроллер получит его вместо этой проблемы.

Ответ 5

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

Подход, с которым я экспериментирую (что делает его несколько проще для написания тестов, а также), заключается в том, что для каждой страницы, содержащей логику, есть объект контекста vanilla js (и он имеет преимущество очень легко разбивать и делегировать к различным объектам). Затем контроллеры в основном вызывают методы для объектов контекста, когда они получают события, и имеют методы для их извлечения битов представления или внесения изменений в представление.

Я из фона wpf и люблю думать о контроллерах как о файлах с кодом. Диалог между презентатором/контекстом и представлением намного больше, чем wpf (поскольку у вас нет привязки + шаблона данных), но это не так уж плохо.

Еще одна проблема, которую мне еще не пришлось решать - использование синглтонов для контроллеров вызывает проблемы для повторного использования элементов пользовательского интерфейса на одной странице. Это похоже на серьезный недостаток дизайна. Общее решение, которое я видел, (еще раз), чтобы собрать все в один файл, и в этом случае полностью отключить контроллер. Ясно, что не очень хороший подход, как только вещи начинают усложняться.

Похоже, что получение всего состояния из контроллера должно помочь, хотя и у вас будет второй уровень объектов контекста. Верхний уровень в основном просто назначил бы уникальный идентификатор для каждого представления и имел бы карту контекста = > просмотр и предоставление отправки отдельным контекстным методам - ​​в основном это будет фасад. Тогда состояние для каждого представления будет рассмотрено в объектах, отправленных в. Хороший пример того, почему статика зла!

Ответ 6

Я использую ExtJS 4 MVC каждый день. Вместо кода спагетти у меня есть элегантное приложение MVC, которое четко определяет разделение контенов и смехотворно просто поддерживать и расширять. Возможно, ваша реализация должна быть немного изменена, чтобы в полной мере использовать преимущества подхода MVC.