Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 17.05.2012, 13:07
Новичок на форуме
Отправить личное сообщение для Alex Danilov Посмотреть профиль Найти все сообщения от Alex Danilov
 
Регистрация: 17.05.2012
Сообщений: 7

Как правильно спроектировать приложение?
Добрый день, коллеги!

Я проектирую простое приложение на основе Layout Browser
http://dev.sencha.com/deploy/ext-4.1...t-browser.html

В системе есть сущности: категории, товары, заказы.
Общий код для создания лайаута находится в отдельном файле и при клике на ветку дерева загружает класс
var m = Ext.create('Catalog.modules.имя_класса');
m.getIndexPanel()


Каждый модуль имеет такую структуру:
Ext.define('Catalog.modules.category', {

    getStore: function() {
        var me = this;

        if (me.store === undefined) {
            Ext.define('category', {
                extend: 'Ext.data.Model',
                fields: ['id', 'name', 'code']
            });
            me.store = Ext.create('Ext.data.Store', {
                model: 'category',
                proxy: {
                    type: 'rest',
                    url : '/catalog/products/',
                    reader: {
                        type: 'json',
                        root: 'items'
                    }
                },
                autoLoad: true,
                autoSync: true
            });
        }

        return me.store;
    },

    getIndexPanel: function() {
        var me = this;
        me.getStore();

        var rowEditing = Ext.create('Ext.ux.grid.plugin.RowEditing', {
            clicksToMoveEditor: 1,
            autoCancel: false
        });

        me.grid = Ext.create('Ext.grid.Panel', {
            title: 'Категории',
            store: me.store,
            height: 700,
            forceFit: true,
            columns: [
                {
                    text: 'Название категории',
                    dataIndex: 'name',
                    sortable : true,
                    editor: {
                        allowBlank: false
                    }
                },
                {
                    text: 'Код',
                    dataIndex: 'code',
                    editor: {
                        allowBlank: false
                    }
                }
            ],
            viewConfig: {
                stripeRows: true
            },
            tbar: [
            {
                text: 'Добавить',
                iconCls: 'add-item',
                handler: function() {
                    if (rowEditing.editing) return false;

                    var item = Ext.create('category', {

                    });
                    me.store.insert(0, item);
                    rowEditing.startEdit(0, 0);
                }
            }, {
                itemId: 'remove',
                text: 'Удалить',
                iconCls: 'remove-item',
                handler: function() {
                    var sm = me.getSelectionModel();
                    rowEditing.cancelEdit();
                    Ext.Msg.show({
                         title: 'Удалить запись?',
                         msg: 'Вы действительно хотите удалить выделенные записи?',
                         buttons: Ext.Msg.YESNO,
                         icon: Ext.Msg.QUESTION,
                         fn: function (btn){
                            if (btn === 'yes') {
                                me.store.remove(sm.getSelection());
                                me.store.sync();
                                if (me.store.getCount() > 0) {
                                    sm.select(0);
                                }
                            }
                         }
                    });
                }
            },{
                text: 'Обновить',
                iconCls: 'refresh',
                handler: function() {
                    me.store.load();
                }
            }],
            plugins: [
                rowEditing
            ]
        });

        return me.grid;
    }
});


Модуль товаров:
Ext.define('TourOffice.modules.products', {

    getStore: function() {
        var me = this;

        if (me.store === undefined) {
            Ext.define('product', {
                extend: 'Ext.data.Model',
                fields: ['id', 'category_id', 'name']
            });
            me.store = Ext.create('Ext.data.Store', {
                model: 'product',
                proxy: {
                    type: 'rest',
                    url : '/catalog/products/',
                    reader: {
                        type: 'json',
                        root: 'items'
                    }
                },
                autoLoad: true,
                autoSync: true
            });

            var categories = Ext.create('Catalog.modules.categories');
            me.categoriesStore = categories.getStore();
        }

        return me.store;
    },

    getIndexPanel: function() {
        var me = this;
        me.getStore();

        var rowEditing = Ext.create('Ext.ux.grid.plugin.RowEditing', {
            clicksToMoveEditor: 1,
            autoCancel: false
        });

        // create reusable renderer for categories
        Ext.util.Format.comboRenderer = function(combo){
            return function(value){
                var record = combo.findRecord(combo.valueField, value);
                return record ? record.get(combo.displayField) : combo.valueNotFoundText;
            }
        }
        var categoriesCombo = new Ext.form.ComboBox({
            typeAhead: true,
            triggerAction: 'all',
            lazyRender:true,
            mode: 'local',
            store: me.categoriesStore,
            valueField: 'id',
            displayField: 'name'
        });

        me.grid = Ext.create('Ext.grid.Panel', this, {
            title: 'Товары',
            store: me.store,
            height: 700,
            forceFit: true,
            columns: [
                {
                    text: 'Название товара',
                    dataIndex: 'name',
                    sortable : true,
                    editor: {
                        allowBlank: false
                    }
                },{
                    text: 'Категория',
                    dataIndex: 'category_id',
                    editor: {
                        editor: currenciesCombo,
                        renderer: Ext.util.Format.comboRenderer(categoriesCombo), // pass combo instance to reusable renderer
                        allowBlank: false
                    }
                }
            ],
            viewConfig: {
                stripeRows: true
            },
            tbar: [
            {
                text: 'Добавить',
                iconCls: 'add-item',
                handler: function() {
                    if (rowEditing.editing) return false;
                    
                    var item = Ext.create('product', {
                       
                    });
                    me.store.insert(0, item);
                    rowEditing.startEdit(0, 0);
                }
            }, {
                itemId: 'remove',
                text: 'Удалить',
                iconCls: 'remove-item',
                handler: function() {
                    var sm = me.getSelectionModel();
                    rowEditing.cancelEdit();
                    Ext.Msg.show({
                         title: 'Удалить запись?',
                         msg: 'Вы действительно хотите удалить выделенные записи?',
                         buttons: Ext.Msg.YESNO,
                         icon: Ext.Msg.QUESTION,
                         fn: function (btn){
                            if (btn === 'yes') {
                                me.store.remove(sm.getSelection());
                                me.store.sync();
                                if (me.store.getCount() > 0) {
                                    sm.select(0);
                                }
                            }
                         }
                    });
                }
            },{
                text: 'Обновить',
                iconCls: 'refresh',
                handler: function() {
                    me.store.load();
                }
            }],
            plugins: [
                rowEditing
            ]
        });

        return me.grid;
    }
});


Вопрос - правильно ли я планирую структуру модулей?
В товарах есть создание класса категории categoriesStore для того, чтобы в комбобокс в листинге товаров подставилась категория, а не ID.

Прошу подсказать, есть ли недочеты или ошибки, как правильно построить такую структуру?
Ответить с цитированием
  #2 (permalink)  
Старый 17.05.2012, 13:46
С++/C# modest developer
Отправить личное сообщение для nekto_O Посмотреть профиль Найти все сообщения от nekto_O
 
Регистрация: 07.11.2011
Сообщений: 244

приложение, в котором логика, представление и модель соседствуют (все в одном файле), как правило плохо масштабируется в дальнейшем. Дочерние компоненты обычно создаются во время инициализации(которую вызывает конструктор), у вас видимо в любое время. Но это только то что сильно бросается в глаза. А вообще похоже что вы уже приступили к реализации, а задаете вопрос
Сообщение от Alex Danilov
правильно ли я планирую структуру модулей
реализацией (написанием кода) обычно занимаются после того как спроектирован интерфейс и структура модулей.
Ответить с цитированием
  #3 (permalink)  
Старый 17.05.2012, 15:11
Профессор
Отправить личное сообщение для DjDiablo Посмотреть профиль Найти все сообщения от DjDiablo
 
Регистрация: 04.02.2011
Сообщений: 1,815

Не буду столь критичен как Nekto_O,
Помоему для совсем маленького проекта не так уж и плохо.

но насчёт масштабируемости он прав, более дальновидным будет реализация модуля как папки с компонентами модуля..

Привиду пример, это частный случай, который позволяет грузить множество форм(модулей), с одинаковой структурой модуля.
Ext.define('app.modules.mngr', {
	    singleton: true,
        getModule: function(me,name) {
           //подгрузим типовые необходимые файлы для модуля
	   	   Ext.require([
                   "app.modules."+name+".view",
                   "app.modules."+name+".model",
                   "app.modules."+name+".store",
                   //"app.module."+name+".controller"-если нужен
           ],function(){
                   // создадим и добавим view
                   var myComponent = new app.modules[name].view();
                   me.add( myComponent );

                   //подключаем здесь ещё что нибудь
            }
        }
        // вспомогательные функции,если надо (унечтожения модуля, хелперы и тд)       
}

//применение
app.module.mngr.getModule(цель куда поместим загруженный модуль, имя модуля );


В вашем случае структура модулей может различатся.
как варианты
1)грузить только controller модуля, который будет грузить всё остальное. (самый гибкий)
2) файлы подлежащие загрузки описывать в module.cfg. (если у вас 100 видов документов по типу 1с,и их часто изменяют, то быстрее писать конфиги с нужной инфой, чем контролёры)
3) также некто не запрещает использовать requires внутри уже загруженных менеджером компонентов
__________________
Лучше калымить в гандурасе чем гандурасить на колыме

Последний раз редактировалось DjDiablo, 17.05.2012 в 16:17.
Ответить с цитированием
  #4 (permalink)  
Старый 18.05.2012, 01:08
Новичок на форуме
Отправить личное сообщение для Alex Danilov Посмотреть профиль Найти все сообщения от Alex Danilov
 
Регистрация: 17.05.2012
Сообщений: 7

nekto_O, DjDiablo,
Спасибо за ответы, но я не понимаю, зачем модуль, содержащий 3-5 методов разбивать на файлы моделей, контроллеров? Методы будут следующие: отображение списка сущностей, редактирование выбранной сущности, получение Store для заполнения данных combobox в связанных таблицах.
Ответить с цитированием
  #5 (permalink)  
Старый 18.05.2012, 12:49
Профессор
Отправить личное сообщение для DjDiablo Посмотреть профиль Найти все сообщения от DjDiablo
 
Регистрация: 04.02.2011
Сообщений: 1,815

Там не 3-5 методов !!! А 3-5 классов, обьявленных внутри методов (это большая разница !!!).
В ООП принято за правило, каждый класс выносить в отдельный файл.
Как минимум это способствует прозрачности и читаемости кода.

из самых очевидных недостатков вашего подхода "Всё в одном".
- С большим обьёмом кода сложно работать. Если такой модуль разрастется, его всё равно придётся бить на более мелкие.
- С этим модулем почти невозможно работать в команде.
- Если нужно сделать какой нибудь отчёт, и потребуется только store , то ради этого store придётся грузить весь модуль.


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

p.s.
Цитата:
А 3-5 классов, обьявленных внутри методов
Если поискать похожий паттерн, то это можно назвать фабричным методом. Однако фабрики не подразумевают объявление класса внутри функции, это скорее даже не обычно, а в большинстве языков невозможно. Обычно ограничиваются созданием экземпляров класса.
__________________
Лучше калымить в гандурасе чем гандурасить на колыме

Последний раз редактировалось DjDiablo, 18.05.2012 в 13:42.
Ответить с цитированием
  #6 (permalink)  
Старый 18.05.2012, 19:16
Новичок на форуме
Отправить личное сообщение для Alex Danilov Посмотреть профиль Найти все сообщения от Alex Danilov
 
Регистрация: 17.05.2012
Сообщений: 7

DjDiablo,
Вас понял, спасибо.

А как по такому принципу сделать?

2) файлы подлежащие загрузки описывать в module.cfg. (если у вас 100 видов документов по типу 1с,и их часто изменяют, то быстрее писать конфиги с нужной инфой, чем контролёры)
Ответить с цитированием
  #7 (permalink)  
Старый 18.05.2012, 23:28
Профессор
Отправить личное сообщение для DjDiablo Посмотреть профиль Найти все сообщения от DjDiablo
 
Регистрация: 04.02.2011
Сообщений: 1,815

для вашего проекта этого не нужно.

Когда я писал про конфиг я вообще то думал о проекте над которым сейчас работаю.
И имел я ввиду не просто конфиг а полноценный internal DSL,
В моём случае этот декларативный язык управляет структурой и поведением сущности на всех уровнях.
Такой подход это смесь декларативного и предметно ориентированного программирования.

К сожалению я не смогу нормально описать это решение в рамках форума.

Если интересно самому реализовать что то подобное, то пишите в личку. Сформилирую задание по клиенту, с подсказками в решении.
Но без лишний нужды я бы на вашем месте не заморачивался, в моём случае просто по другому невозможно. У вас же, всё намного проще.
__________________
Лучше калымить в гандурасе чем гандурасить на колыме

Последний раз редактировалось DjDiablo, 19.05.2012 в 01:10.
Ответить с цитированием
  #8 (permalink)  
Старый 22.05.2012, 19:00
Новичок на форуме
Отправить личное сообщение для Alex Danilov Посмотреть профиль Найти все сообщения от Alex Danilov
 
Регистрация: 17.05.2012
Сообщений: 7

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

В grid это listener:
listeners: {
                rowdblclick: {
                    fn: function(grid, rowIndex, e) {
                        var item = grid.getAt(rowIndex);
                        me.getEditForm(item);
                    }
                }
            }

А вот что должно быть в getEditForm смутно представляю. Наверное, там должно создаваться окно с формой редактирования. Но куда рендерить это? Может где-то есть пример?

Последний раз редактировалось Alex Danilov, 22.05.2012 в 19:02.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как правильно прицепить обработку события slowklg Events/DOM/Window 6 15.03.2012 16:20
Как правильно очистить maxlength в input? Маэстро Events/DOM/Window 10 22.06.2011 18:14
Как правильно задать ID в создаваемом элементе ? Indiana Events/DOM/Window 15 31.10.2010 16:15
Подскажите как правильно оформить код frolvict Общие вопросы Javascript 4 30.04.2010 10:51
Как правильно оформить Send() Алекс97 AJAX и COMET 20 30.10.2008 19:19