aralejs / aralejs.github.io

开放、简单、易用的前端基础类库
http://aralejs.github.io
MIT License
1.37k stars 321 forks source link

Events 增加 mixTo 方法 #33

Closed lifesinger closed 12 years ago

lifesinger commented 12 years ago

eventsclass, optionsbase 中独立出来后,面临一个问题:

define(function(require) {

    var Events = require('events');

     function MyClass() { ... }

     // 如何将 Events 提供的功能,混入到 MyClass 中?

});

一种方式是,再引入 classbase 模块,然后通过 Class.createBase.extend 中的 Implements 属性来指定混入 Events:

define(function(require) {

    var Events = require('events');
     var Class = require('class');

  var MyClass = Class.create({
       Implements: Events,
       ...
   });

});

但对于很多工具类,比如 Position 或无线端的 Storage 等来说,并不是 function class, 用 Class.create 来创建意义不大。这种情况下,传统的一个解决思路是:

define(function(require) {

    var Events = require('events');
     var seed = require('seed');

     var Storage = {

         set: ...
         get:... 

     };

    // 通过 seed 或某个类,来提供 mix 等方法
    // 或者自己在 Storage 中实现一个 mix 方法
    seed.mix(Storage, Events.prototype);

});

很显然,通过 seed 或 util 等思路来解决,比较适合 YUI, KISSY 等一站式类库(可以直接放在 Y 和 S 中)。但对 Arale 的思路来说,这并不妥。Arale 没有所谓的 seed 或 core,要按上面的思路去做的话,会导致 Events 在使用时,得强依赖另一个 util 或 seed 组件,然而很可能仅仅只用到一个 mix 方法。

这个问题与颂赞等人讨论过,无线端不少工具类组件需要 Events,并不需要 Class 和 Base.

这问题一直萦绕心头,今天偶然看到一篇技术文章里提到 IoC(控制反转),莫名就联想到了这个问题,而且发现 jQuery 的 appendTo 等方法也有类似的意思,因此就想到:

不如让 Events 自己提供 mixTo 方法

立刻感觉云散花开,很自然的就可以:

define(function(require) {

     var Storage = {

         set: ...
         get:... 

     };

   // 让 Storage 方法拥有  on/off/trigger
    require('events').mixTo(Storage);

  return Storage;
});

代码明显精简、漂亮多了。更重要的是,让 Storage 的依赖减少,更解耦了。

想起陈皓的一篇文章:http://coolshell.cn/articles/7236.html

解耦,解耦,解耦。

Arale 类库的设计思想里,也有一段很重要的:

不追求代码的零重复,更追求组件的独立性。

如果大家认可,我觉得接来下我们可以进一步约定,凡是可以 mix 给普通对象(比如 var obj = {})用的组件,比如 Events 这种,默认应该都提供 mixTo 方法。

PraiseSong commented 12 years ago

确实,不能因为只用到一个mix方法而require一个class或base,但是这样的话,是不是有些职责混乱?Events的职责主要提供一套事件机制,如果冒出个mixTo,感觉有些怪。另外我觉得如果大家都同意的话,移动平台也可以直接使用原生的枚举方法

lifesinger commented 12 years ago

这是个很有意思的话题,越来越觉得,代码零重复的追求,其实不利于解耦。

比如有理论洁癖的 YUI3,如果一个模块 A 用到 xx 方法,另一个模块 B 也需要用到 xx 方法,那么 YUI3 会把这个 xx 方法拎取出来,放到一个更基础的 C 模块中去。

看起来多美妙呀。

然而实际上,越追求代码零重复,会让各个模块之间的关系越复杂:

// 箭头表示依赖
A -->  B  --> C ...
B --> D --> Q ...
Q - > Z -> A ...

最后,可以说因为追求代码零重复,使得所有代码都被绑定到一起了,成为了一个巨无霸!

问题是,巨无霸经常并不是我们需要的!比如 ExtJS、比如 YUI3, 比如 Windows 操作系统⋯⋯

反观 jQuery 社区,以及 NodeJS 社区,他们更追求独立,而不是代码零重复!

underscore 和 jquery 存在交集,express 和 node/lib 也存在交集,backbone 里有些代码,在 jquery 里有实现,乱七八糟的呀⋯⋯

然而正是这种“适量重复”,保持了各个组件的独立性和专注性,一独立一专注,就可以像 Unix 中的模块一样灵活组装起来,最后可做的事情,往往比巨无霸能做的事情多,而且性能很可能更好⋯⋯

适量重复,非常有意思。何为适度?权衡在心,目前这个心是依赖、是独立、是组件的粒度、是直觉。

semious commented 12 years ago

"适量重复"对于一个实际的需求,有时候比较难衡量的, 比如说,A个组件需要调用B的一个位置组件的计算DOM元素位置的一个方法,但是他发现,B的那个组件实际是计算DOM元素的位置其实是调用jquery的DOM元素位置的方法,A的组件为了计算DOM元素位置组件,条用了B组件同时,间接也调用了Jquery,A组件的开发人员会想,我只是为了计算DOM元素位置,却莫名调用了两个js类库(B和jquery),这个和自己实现起来不一定合算,但是如果自己实现的话,又违背了代码零重复的原则。碰到这种场景,我觉得A组件的开发人员会比较纠结... 还有一种情况,如果有两个方法,一个需要调用B组件,一个需要jquery,然后开发人员,B组件的实现方法不过在jquery上又封装了一层,这样的话,是否需要再调用B组件?直接jquery是否能更好,当然这个前提是开发人员比较了解B组件的实现方法... 更加复杂的场景是有三个方法,B组件都能提供,不过开发人员发现,其中2个方法,B组件不过是调用jquery实现的,这样还不如直接调用jquery来实现,还有一个方法确实是B组件原生提供的,不过开发人员可能会想,这个实现比较简单,我自己实现可能比只是为了实现这个方法调用B组件,不太合算...还不如自己实现,不过如果这样的话,感觉就比较乱...

我觉得在碰到实际开发的场景时候,"适量重复"可能更多靠的是经验和对一个具体场景的判断

lifesinger commented 12 years ago

@semious 我的想法是这样的:

A 组件是否调用 B 组件,取决于 A 组件在调用 B.xxMethod 时,B.xxMethod 方法是不是 B 组件的核心功能,如果是,就果断调用,没必要在 A 组件里自己再实现一把,如果 xxMethod 不是 B 组件的核心功能,则可以考虑在 A 组件里自己实现一个。

是否核心功能,取决于我们对组件的定位。比如我们对 jQuery 的定位是 DOM/Ajax/Anim 操作类库,那么凡是需要用到这些操作时,大胆调用就好。但是,如果仅仅需要调用 $.extend$.each, 则需要权衡考虑是否有必要。如果 A 组件对 jQuery 的依赖仅仅是 extend 等辅助方法,我推荐 A 组件自己去实现就好。

适量重复,看似很难把握,但只要放到具体代码中来权衡,我觉得还是可以找到比较合适的权衡点的。

由于 Events 组件已经添加 mixTo 方法,该 issue 先关闭,不过大家可以继续讨论。

antife-yinyue commented 12 years ago

每天看你们的讨论也是种享受,有时候会让自己瞬间豁然~

jQuery 的 Anim,要是能使用 CSS3,再加 fallback 就好了,我就不用费神自己开发~

非常希望能得到大侠们的指点,每天进步一点点~

https://github.com/jsw0528/Transition http://mrzhang.me/blog/jquery-transition.html

lifesinger commented 12 years ago

@jsw0528 建议建一个 issue 到 jquery 的 github 上,我记得曾经有人提出,后来不知什么原因没上,可以再去提提。

antife-yinyue commented 12 years ago

@lifesinger 他们把 issue 关了~