对TypeScript版PureMVC的优化

5 篇文章 0 订阅
2 篇文章 1 订阅

官网位置:http://puremvc.org/

按接口逐一介绍所作的优化内容吧,没列举的亦可能有改动过,但未作大的改动。

1. ICommand

原版command中execute方法接受的参数是INotification对象,从INotification中可以获取到body, name和type,这种封装导致puremvc在派发消息时,你需要不停地去组装和拆分消息,有点繁琐,所以我将execute的参数改为了不定参数,可传可不传,如果sendNotification时传递了参数,则execute可以直接接受真实的形参而非是从一个被封装的INotification对象中去取Body然后再按键值去获取消息数据

module puremvc {

    export interface ICommand extends INotifier {
        execute(...args: Array<any>): void;
    }
}

// for instance

class TestCommand extends puremvc.SimpleCommand {

    execute(x:number, y:number, z:number):void {
        console.log("x:" + x, "y:" + y, "z:" + z);
    }
}

puremvc.Facade.getInstance().sendNotification("TestCommand", [1, 2, 3]);

// for one argument
puremvc.Facade.getInstance().sendNotification("TestCommand", 0);
// or 
puremvc.Facade.getInstance().sendNotification("TestCommand", [0]);
// both ok

2. INotification

这玩意儿被我删了,反正没啥用

3. IMediator

原版puremvc中,View 是通过 listNotificationInterests 方法获取 mediator 关心的消息列表,然后在命令被派发时,通过调用mediator 的 handleNotification 来响应消息,而 handleNotification 中,则必须通过 if else 或 switch 的格式来响应消息,这个机制也太繁琐,所以我对它也进行了重构

我在 mediator 中定义了 notificationInterests:Array<IObserver> 属性,mediator 被注册时,依然会调用 listNotificationInterests 方法,但这个方法并不返回命令列表,取而代之的是,是在这个方法中,可直接调用 handleNotification 来注册命令和回调,handleNotification 会调用 registerObserver 来注册观察者,观察者信息会被保存到 notificationInterests 属性中,我增加了一个 removeNotificationInterests 方法,它在 mediator 被移除时将会调用,被调用时会自动注销所有在 listNotificationInterests 中通过 handleNotification 注册的事件

这个改动终结了 handlerNotification 中 if else 或 switch 的写法,方便了不少,下面是简单的例子

// register mediator

class TestMediator extends puremvc.Mediator {

    // 注意返回类型是 void 了
    listNotification():void {
        this.handlerNotification("TestMessageA", this.$onTestMessageA);
        this.handlerNotification("TestMessageB", this.$onTestMessageB);
    }

    // 响应 TestMessageA
    private $onTestMessageA(x:number, y:number, z:number):void {
        console.log("x:" + x, "y:" + y, "z:" + z);
    }

    // 响应 TestMessageB
    private $onTestMessageB(a:string):void {
        console.log("a:" + a);
    }

    // 你不需要重写 removeNotificationInterests 方法,它自己会在 onRemove 时帮你移除回调
}

// send messages
puremvc.Facade.getInstance().sendNotification("TestMessageA", [1, 2, 3]);
puremvc.Facade.getInstance().sendNotification("TestMessageB", "yes");

// 不需要写 if else 和 switch 方便多了吧?

4. IView

由于 INotification ,ICommand 和 IMediator 的改动,所以这个类的重构比较大,总的来说有以下几点

a: registerObserver 方法

这个方法原本接受的参数有两个,1是notificationName:string, 2是observer:IObserver ,改动后则接受5个参数

/**
 * 首先,参数的写法是参考的flash as3中的EventDispatcher,没办法,as3的事件太好用了
 * @receiveOnce: 是否只响应一次,默认为false
 * @priority: 优先级,优先响应级别高的消息,值越大,级别越高,默认为1,有这个参数的存在,若你想控制
 * 回调函数的执行顺序,则会非常容易
 */
registerObserver(name: string, method: Function, caller: Object, receiveOnce: boolean = false, priority: number = 1): IObserver {

}

b: notifyObservers 方法

这个方法原本只接受一个参数,就是notification:INotification,改动后则接受3个参数

/**
 * @name: 命令名字
 * @args: 参数列表,可缺省,或为任意类型的数据
 * @cancelable: 事件是否允许取消,默认为false
 */
notifyObservers(name: string, args?: any, cancelable: boolean = false): void {

}

值得一说的是 cancelable,改动后的命令是允许被取消的,例子如下

puremvc.Facade.getInstance().registerObserver("TestMessage", handlerA, null, false, 1);
puremvc.Facade.getInstance().registerObserver("TestMessage", handlerB, null, false, 2);

function handlerA(x:number) {
    console.log("handler a is executed");
}

function handlerB(x:number) {
    console.log("handler b is executed");

    // 中断消息
    puremvc.Facade.getInstance().notifyCancel();
}

puremvc.Facade.getInstance().sendNotification("TestMessage", 5, true);

// 在这个例子中,只会打印如下消息

"handler b is executed"

// 原因之一是 observer 在被注册时,handlerB 的优先级比 handlerA 高,所以 handlerB 先执行
// 原因之二是 "TestMessage" 在被派发时,指定的 cancelable 是 true,而 handlerB 中调用了notifyCancel 方法,所以消息在 handlerB 响应结束之后,被中断传递了

这里有个需要注意的是,我公开了 registerObserver 方法,但并没有去给命令作确保执行的处理,所以,如果你即注册了命令,又在 mediator中注册了回调,那么,你在 mediator 中使用 notifyCancel 的时候,需要特别注意这个问题,如果你希望命令使终都能被执行,则建议你先注册命令,再注册中介者

c: removeObserver 方法

参考 flash as3 中的 EventDispatcher ,很容易就能想到,removeObserver 变成了下面这个样子了

removeObserver(name: string, method: Function, caller: Object): void {
}

d: $isCanceled:boolean 属性

这个属性是用来实现 notifyCancel 的逻辑的

e: $observers:Array<boolean | IObserver > 属性

这个数组,在原版puremvc中,是 Array<IObserver>,为什么我要加上 boolean 呢?因为原版的puremvc中,每次执行 notifyObserver 时,都会对 objservers 进行复制,但如果消息在派发过程中,没有任何方法被注册或注销的话,observers 属性就不会发生变化,这时这个复制就是多余的

所以,我对它这部分作了性能优化,我在 Array[0] 中保存了一个 boolean 默认为 false ,在 notifyObserver 被调用时,我会将这个 boolean 赋值为 true ,执行完毕后,再重置为 false ,当 registerObserver 或 removeObserver 被调用时,我先读取 Array[0] 的值,若为 true ,则说明这个消息正在执行,此时 notifiyObserver 和注册注销会形成干扰,这时候就对 $observers 数组进行复制,复制完再将新的数组中的 Array[0] 重置为 false ,因为后面的注销和注册行为操作的是新数组,己不会再对本次的 notifyObserver 产生干扰了。

这步优化可以省去很多数组复制的操作

5 IFacade

由于上述的改动,外观类中的接口当然也需要一起被改变,不过我在 Facade 中还开放了 registerObserver 和 removeObserver 方法,开放这两个方法的原因,命令派发虽然可以从任何地方发起,但命令的响应除了 ICommand 之外,却只能存在于 mediator 中,这种设定迫使不得不去定义一些本来没必要存在的命令或中介者,带来的影响除了性能的下降之外,还有额外增多的代码工作量,基于此,有些人选择放弃了puremvc,还有些人选择写一个全局的事件派发器,而我选择了重构puremvc /手动滑稽

附git地址,欢迎下载使用:https://github.com/syfolen/ts-puremvc  main 分支

结语:遵重原著版权,puremvc版权归原作者 Frederic Saunier 所有,若有侵犯,烦告知

PureMVC Standard Framework for TypeScript - Copyright © 2012 Frederic Saunier

PureMVC Framework - Copyright © 2006-2012 Futurescale, Inc.

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值