ext js 4使用控制器中的模块设计模式

时间:2014-03-09 12:40:53

标签: design-patterns module extjs4

在ext js中开发控制器时,是否建议使用模块模式?

我相信通过这样做,我们实现了以下目标:

  

1)抽象出使用中的框架。业务逻辑已实施   在模块中。模块不(至少不应该),知道任何事情   关于框架功能。

     

2)暴露依赖性。框架应该为模块提供   所需数据。模块应该只运用这些知识。

     

3)更容易进行单元测试。您的测试不依赖于框架   知识。您只测试业务场景。

模块模式在sencha教程中非常流行,Ext之前的版本中的示例是4.0,但我在最近的教程中找不到任何对它的引用。

有什么变化吗?我错过了什么吗? 你使用这种做法吗?

感谢您的输入

编辑:

以下是主/细节控制器的代码 它将选定的行加载到详细信息表单中,然后触发'mycustomevent' 如果表单中的数据无效,它还会阻止网格行选择。

我添加了两种代码变体 1)简单的ext js实现。
2)使用模型模式的相同实现。

=== Ext Js Controller ===

Ext.define('Patterns.controller.MoviesMasterDetail', {
    extend : 'Ext.app.Controller',
    views : ['Patterns.view.Movies',
        'Patterns.view.Detail'],
    refs : [{
            ref : 'Detail',
            selector : 'detail'
        }
    ],
    init : function () {
        this.control({
            'movies' : {
                beforeselect : this.onBeforeSelect,
                selectionchange : this.onMovieSelected
            },          
            'detail' : {
                'mycustomevent' : this.onMyCustomEventWithArgs
            }           
        });
    },
    onMyCustomEventWithArgs: function(arg)  {
        alert(arg);
    },
    onBeforeSelect : function () {
        var detailForm = this.getDetail().getForm(),
            hasRecord = detailForm.getRecord() != null;
        if(hasRecord) {
            return detailForm.isValid();            
        }

        return true;
    },
    onMovieSelected : function (thisSelectionModel, selected, eOpts) { 
        var detail = this.getDetail();
        var detailForm = detail.getForm();
        var rec = selected[0];
        rec.data['descr'] = 'modified';
        detailForm.loadRecord(selected[0]);
        detail.fireMyEvent('from controller');
    }
});

===具有模块模式的Ext Js控制器===

Ext.define('Patterns.controller.MoviesMasterDetailModule', {
    extend : 'Ext.app.Controller',
    views : ['Patterns.view.Movies',
        'Patterns.view.Detail'],
    refs : [{
            ref : 'Detail',
            selector : 'detail'
        }
    ],
    init : function () {
        this.control({
            'movies' : {
                beforeselect : this.onBeforeSelect,
                selectionchange : this.onMovieSelected
            },
            'detail' : {
                'mycustomevent' : this.onMyCustomEventWithArgs
            }
        });
    },
    onMyCustomEventWithArgs: function(arg)  {
        alert(arg);
    },
    onBeforeSelect : function () {

        var me = this,
            detailForm = me.getDetail().getForm(),
            formRecord = detailForm.getRecord();
            module = new Module();

            return module.onBeforeSelect(formRecord, detailForm.isValid, detailForm);
    },
    onMovieSelected : function (thisSelectionModel, selected, eOpts) {
        var detail = this.getDetail();
        var detailForm = this.getDetail().getForm(),
        module = new Module()
        recToLoad = selected[0];

        var loadRecordTupple = {
                    fn: detailForm.loadRecord, 
                    scope: detailForm
                    };


        var fireEventTupple = {
                    fn: detail.fireMyEvent, 
                    scope: detail
                    };

        module.modifyRecord(recToLoad, loadRecordTupple, fireEventTupple );
    }
});

===模块实施===

function Module()
{
    var onBeforeSelect = function(selectedRecord, validationFunc, caller){
        if(!selectedRecord){
            return true;
        }

        return validationFunc.apply(caller);
    };

    var modifyRecord = function(dataToLoad, loadTupple, fireEventTupple, caller){
        dataToLoad.data['descr'] = "modified";

        loadTupple.fn.apply(loadTupple.scope, [dataToLoad]);
        fireEventTupple.fn.apply(fireEventTupple.scope, ["from module"]);
    }

    this.onBeforeSelect = onBeforeSelect;
    this.modifyRecord = modifyRecord;
}

2 个答案:

答案 0 :(得分:2)

丹尼尔斯 你问: “在ext js中开发控制器时,是否建议使用模块模式?” 我的答案是完全的,是的。虽然,ExtJs并没有在我看过的任何地方的作品中提出它。

我在CO的Denver举行的Javascript Meetup上做了一个演示,展示了我编写的库的用法,该库强制执行Modular(构造函数驱动的)MVC设计模式。

该演示文稿是ExtJs Architect应用程序的主要开发人员之一。他告诉我(不记录)模块化MVC设计模式的使用是ExtJs的用武之地。所以也许我们会在ExtJs 5文档中看到这个设计模式。但截至今天,ExtJs仍然建议将所有控制器放在一个文件夹中,并将视图放在一个文件夹中,并将模型放在一个文件夹中并存储在....你得到它。在大型Web应用程序开发方面,您和我以及其他一些人所知道的将无法正常工作。

这变成了一个咆哮,让我切入追逐(我的同事注意到这篇文章并希望我分享一些见解): 模块化设计模式完全可以与ExtJs一起使用,并且它非常有效。在使用ExtJs Framework时,您只需编写自己的库来强制执行该模式。我正在使用自己的库,它有:

  1. 轻松完成单元测试
  2. 提高生产力并允许我们设定可靠的交付日期并与之相遇
  3. 允许2个人完成4个工作
  4. 高度分离的代码,依赖于Javascript的事件驱动性
  5. 为了给出我的“咆哮”观点,我作为承包商($$$)开发了Web应用程序(SAAS和企业内部网应用程序)已有20年。在过去的20年里,我使用过YUI,DOJO,ExtJs,Backbone和其他一些人。我为DOJO,ExtJs& amp;编写了我的模块化MVC设计模式库的版本。 BackBone(也适用于ActionScript,但这是另一个故事)。

    ExtJs有一个非常稳定的框架(如果你查看它们的源代码,你会看到编码风格的一些例外),它们适用于大多数设计模式。

    那么,再次回答你原来的问题: “在ext js中开发控制器时,是否建议使用模块模式?” 我的答案是完全的,是的。

    ============= 最糟糕的Javascript建议,我一遍又一遍地听到: “为什么我们不在JQuery中全部完成”

    对DanielS评论的回答:

    DanielS,我为我的回复延迟而道歉,我会尽可能地为您提供步骤。在每件作品之后,请发一个问题(如果有的话),我们可以继续谈话。

    我的方法是首先创建一个JSON Constructor对象,该对象将反映我的Web应用程序的布局(这是Web应用程序构造函数):

    {
    confiiguration: {
        modules: [
            {
              "config": "modules/HelloWordlModule/config/helloWorldConfig.json"
              "namespace": "Modules.HelloWorldModule.HelloWorld" // Namespace of the modules controller
            }
        ]
    }
    

    }

    然后我会创建一个类(这是库启动的地方),它将解析json对象,并通过nameSpace值Ext.require模块,然后在Ext.require语句的回调中,我将实例化模块将路径发送到模块配置文件(在“config”值中找到)作为构造函数参数(Ext.create(Modules.HelloWorldModule.HelloWorld,{configEndpoint:config});)。在实例化的Module的控制器中,我会发出一个ajax请求来获取模块的JSON配置(使用商店和模型来管理ajax请求)。

    从模块发送事件时: 创建一个扩展Ext.app.Controller的单例类。使用该类的实例来触发事件。 例如:

    Ext.define('Modules.EventsController.ModulesEvents', {
      extend: 'Ext.app.Controller',
      singleton: true,
      /** @property */
      LOGIN_USER: 'loginUser'
    };
    
    Ext.define('Modules.HelloWorldModule.HelloWorld',{
        extend: 'Ext.app.Controller',
        requires: [
            "Modules.EventsController.ModulesEvents" // requiring singleton, instantiates the class 
        ],
    
        onUserLogin: function(){
            var modulesEventBus = this.getModulesEventBus();
            if(modulesEventBus){
                modulesEventBus.fireEvent(modulesEventBus.LOGIN_USER, { username: 'jDoe', email: 'jdoe@website.com'});
            }
        },
    
        getModulesEventBus: function(){
            var eventBus = Modules.EventsController.ModulesEvents;
            if(!eventBus){
                console.log("eventBus is undefined");
            }
            return eventBus;
        }
    });
    

答案 1 :(得分:0)

丹尼尔斯 您添加的代码示例看起来像是一个很好的Web应用程序的良好开端,但我认为我对模块的定义与您在此处的定义不同。我的一个模块是:

  1. 一个小型Javascript应用程序,可以自行运行,无需任何其他模块
  2. 最基本的模块将有一个控制器,一个模型,一个商店和一个视图
  3. 那个模块可以是:

    1. 动态包含在Web应用程序中
    2. 单元在没有完整的Web应用程序的情况下自行测试
    3. 精缩/模糊处理
    4. 关于活动巴士。我通常使用3种类型的事件总线。

      1. 动态加载我的模块的库的事件总线(ApplicationEventBus)
      2. 模块到模块通信的事件总线(ModulesEventBus)
      3. 每个模块的事件总线,用于在该模块自己的实例化类(控制器,视图等)之间进行通信。
      4. 仅凭这一点并不是我创建自己的事件总线的原因。

        1. 我在事件总线中使用的常数作为被解雇或接收的事件的签名。这意味着,我们可以通过引用该签名来侦听和触发任何给定类的事件。
        2. 所以这个:

          this.eventBus.fireEvent("loginUser");
          this.eventBus.on("loginUser");
          

          变为

          this.eventBus.fireEvent(this.eventBus.LOGIN_USER);
          this.eventBus.on(this.eventBus.LOGIN_USER);
          
          1. 所以,如果我需要更改this.eventBus.LOGIN_USER的值,我会的 只需更新一个位置而不是多个位置。这意味着更少 因此,触摸的代码不太可能会引入错误。
          2. 事件在事件总线内“命名空间”,因此不太可能使事件命名与其他被触发的事件发生冲突。