• Home
  • Учебник по ExtJS
  • О сайте
  •  



    Объектно-ориентированный дизайн ExtJS

    Одна из задач, которую ставили себе разработчики библиотеки ExtJS при ее проектировании, была возможность сосуществования с другими JavaScript-библиотеками и фреймворками. Для этого были добавлены удобные методы, помогающие разработчику создавать, наследовать и сопровождать код различных классов. Несмотря на то, что все они были специально созданы для работы с компонентами ExtJS, их можно использовать с любыми объектами JavaScript, в том числе в проектах, не задействующих визуальные компоненты.

    Ext.namespace

    Синтаксис: Ext.namespace( String namespace1, String namespace2, String etc ) : void

    В языке JavaScript пространство имен само является объектом, содержащим список определений других объектов. Правильное использование пространств имен гарантирует, что ваш код не будет конфликтовать с другими библиотеками. Однако, чем больше становится кода в библиотеке, тем глубже иерархия имен и такие классы как Ext.ux.graphing.GraphPanel перестают быть редкостью. В ExtJS существует метод Ext.namespace, который позволяет определить все пространства имен за один вызов, уменьшая не только затраты на поддержку кода, но и сокращая его размер.

    Традиционный код JavaScript, создающий иерархию пространства имен, выглядит следующим образом:

    var Ext = Ext || {}; Ext.ux = Ext.ux || {}; Ext.ux.graphing = Ext.ux.graphing || {}; Ext.ux.soundFx = Ext.ux.soundFx || {}; Ext.ux.maps = Ext.ux.maps || {};

    Того же результата можно достичь вызовом всего одного метода:

    Ext.namespace("Ext.ux.graphing", "Ext.ux.soundFx", "Ext.ux.maps");

    Ext.override

    Синтаксис: Ext.override( Object origclass, Object overrides ) : void

    JavaScript очень гибкий язык, и переопределение метода в нем выполняется простым переназначением его объекта другой функции:

    // создаем функцию function doesStuff() {   alert("Функция один!"); }; // теперь ее перекрываем doesStuff = function() {   alert("Функция два!"); };

    Перекрытие метода класса осуществляется путем переопределения его прототипа:

    function MyClass() {   // конструктор класса } MyClass.prototype.myMethod = function() {   alert("привет"); }; var x = new MyClass(); x.myMethod(); // отобразит "привет" MyClass.prototype.myMethod = function() {   alert("пока"); }; x.myMethod(); // отобразит "пока"

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

    Ext.override – это удобный способ переопределения методов класса за один присест. Следующий пример перекрывает два метода класса Ext.ux.graphing.GraphPanel. Следуя общепринятым правилам языка JavaScript, если в оригинальном классе не содержатся определений методов, то они добавляются. Первым параметром идет класс, который будет изменен, а вторым – JSON объект с методами, подлежащими переопределению:

    Ext.override(Ext.ux.graphing.GraphPanel, {   clearAllPoints: function() {     // выполнить другие действия   },   loadData: function(newData) {     // загрузка новых данных   } });

    Этот простой метод имеет огромное значение при поддержке собственных изменений в чужом коде. Опытные JavaScript-разработчики прекрасно знают, как бывает тяжело использовать модифицированные сторонние библиотеки: каждый их новый релиз порождает необходимость проводить сверку измененных частей и внесения исправлений в собственный код. Используя метод Ext.override, разработчики могут поместить свой код в отдельный файл, связать его со сторонней библиотекой и быть уверенными, что в новом релизе ничего не сломается.

    Ext.extend и соглашения о параметрах конструкторов

    Синтаксис: Ext.extend( Function superclass, Object overrides ) : Function

    или Ext.extend( Function subclass, Function superclass, [Object overrides] ) : Function

    Рассмотренный ранее метод Ext.override выполняет замену реализации на новый метод целиком, а Ext.extend позволяет осуществить полноценное наследование согласно парадигме ООП. Имеются два варианта вызова этого метода, каждый из которых возвращает определение нового класса, содержащего объекты, унаследованные от родительского, определенного в параметре superclass, и перекрывает методы, заданные в параметре overrides. Также он добавляет к новому классу служебный метод override(), который дает возможность перекрывать методы экземпляра класса, и такое же служебное свойство superclass, позволяющее получить доступ к родительскому объекту.

    Библиотека ExtJS имеет ряд соглашений о стиле кодирования, которые позволяют улучшить поддержку и читаемость написанного кода. Одно из них: соглашение о виде конструкторов классов. Практически все конструкторы ExtJS принимают единственный параметр, являющийся объектом нотации в формате JSON и содержащий конфигурацию того или иного компонента. Для приверженцев традиционных объектно-ориентированных языков программирования на первый взгляд это может показаться диким, так как обычно сигнатуры методов (включая конструкторы классов) ожидают явно заданные параметры с жестко определенным типом. Но из-за того, что JavaScript динамически типизированный язык, создавать таким образом объекты с помощью классов не всегда удобно.

    Давайте рассмотрим  на примере, как такое обычное определение будет порождать проблемы при работе с JavaScript. Допустим, что существует версия 1 класса classA, конструктор которого принимает параметр типа String. Спустя три месяца выходит версия 2 этого же класса, в которой первый параметр должен быть типа Date. Без использования компилятора разработчику только и остается перелопачивать весь свой код и менять его, надеясь, что не будут пропущены какие-либо его части, подлежащие изменению. Это наиболее важная и актуальная проблема программирования на JavaScript, и для ее преодоления в ExtJS выбран простой, но эффективный способ: передача в конструкторе единственного параметра, содержащего необходимую конфигурацию. Другим преимуществом такого подхода является возможность простого расширения функциональности – разработчики могут безбоязненно работать с объектами ExtJS, не сомневаясь, что в следующих версиях конструктор будет изменен, и код станет нежизнеспособным.

    Первый вариант вызова Ext.extend принимает два параметра: первый – superclass, указывающий на класс-родитель, второй – overrides, объект содержащий методы, подлежащие добавлению или перекрытию. В том случае, если параметр overrides содержит определение объекта constructor, то он будет использован в качестве конструктора нового класса. Если же объект constructor не задан, то метод Ext.extend создаст новый конструктор, который будет вызывать с теми же параметрами родительский.

    Ниже приведен пример использования Ext.extend. Обратите внимание, что имеются два способа наследования. Первый:

    var newClass = Ext.extend(Ext.form.ComboBox, {   constructor: function(config) { // явное задание конструктора     config.emptyText = "'5' не допускается";     newClass.superclass.constructor.call(this, config);   },   setValue: function(v) {     if (v == 5) { // если v равно 5, сообщить пользователю       alert("'5' не допускается");     } else { // иначе вызываем метод родителя       newClass.superclass.setValue.call(this, v);     }   } });

    Второй:

    function newClass(config) { // конструктор   config.emptyText = "'5' не допускается";   newClass.superclass.constructor.call(this, config); }; Ext.extend(newClass, Ext.form.ComboBox, {   setValue: function(v) {     if (v == 5) { // если v равно 5, сообщить пользователю       alert("'5' не допускается");     } else { // иначе вызываем метод родителя       newClass.superclass.setValue.call(this, v);     }   } });

    Так как все объекты ExtJS имеют одну и ту же форму указания параметров в конструкторе, это позволяет работать с ними без особых усилий: достаточно скопировать все значения объекта config. ExtJS имеет два встроенных метода для выполнения этих действий, которые далее мы и рассмотрим.

    Ext.apply

    Синтаксис: Ext.apply( Object obj, Object config, [Object defaults] ) : Object

    Метод Ext.apply производит копирование каждого члена объекта config в объект obj. Опционально может быть задан параметр defaults, содержимое которого также копируется в объект obj, но перед выполнением копирования объекта config.

    Ext.applyIf

    Синтаксис: Ext.applyIf( Object obj, Object config ) : Object

    Метод Ext.applyIf производит копирование каждого члена объекта config в объект obj, но только в том случае, когда этот член еще не существует в объекте назначения.

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

    function MyClass(config) { // конструктор, который принимает конфигурацию в параметре 'config'   // присвоение некоторых значений по умолчанию, если они не заданы в конфигурации   config = Ext.applyIf(config, {     someValue: defaultValue   });   // а здесь присваиваются значения по умолчанию, игнорирующие параметры конструктора   config = Ext.apply(config, {     someOtherValue: defaultValue   });   // вызов конструктора класса-родителя с передачей новой конфигурации   MyClass.superclass.constructor.call(this, config); } // не забудьте унаследовать родительский класс Ext.extend(MyClass, MyBase, {   // ... });

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

    Продолжение следует…

    Перейти к содержанию Учебника по ExtJS

    Мы помогли Вам? Вы можете поддержать дальнейшее создание учебника по ExtJS.

    3 Responses to “Объектно-ориентированный дизайн ExtJS”

    1. BerdArt:

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

    2. BerdArt:

      Большое спасибо за материал. Продолжайте в том же духе, а то информации на русском языке очень мало…. Думаю, такой учебник пригодится многим. Жду продолжения

    3. Stas:

      Жаль что это материал попал в руки уже после того как бессонные ингулецкие ночи были потрачены на его пнимание =)

    Leave a Reply