您的位置:首页 > 其它

Design Pattern: Not Just Mixin Pattern

2015-07-15 15:35 477 查看
Brief                              

从Mix-In模式到Mixin模式,中文常用翻译为“混入/织入模式”。单纯从名字上看不到多少端倪,而通过采用Mixin模式的jQuery.extend我们是否可以认为Mixin模式就是深拷贝的代名词呢?

本文试图从继承机制入手对Mixin模式进行剖析,若有纰漏请大家指正,谢谢。

The Fact of Inheritance                   

首先让我们一起探讨一下继承机制吧。作为OOP的三个重要特性(Inheritance,Polymorphism,and Encapsulation)之一,继承应该是和Encapsulation关系最紧密。

试想一下,现在我们得到需求分析后要对问题做概念模型设计,过程大概就是从具象化->抽象化->再具象化,而在抽象化时自然而然需要提取具象的共同点得到简单直接的识别模型(如:广东人啥都吃,外国教育就是好),而再具象化时则需要构建更为明确的含义更丰富的认知模型(广东人有的吃猫肉,有的不吃),但它始终是识别模型的具象,也就始终依赖识别模型。

认知模型 多对多 识别模型,如 广东人有的会做生意,有的喜欢打工(广东人有的吃猫肉,有的不吃) 对 广东人会做生意(广东人啥都吃)

PS:认知模型、识别模型均为本人老作出来,识别模型就如文章title,略看后大概知道文章方向;认知模型如文章的content,细看才了解文章的含义。

The Diamond Problem from Multiple Inheritance      

从上文了解到认知模型可对应多个识别模型,那么自然而然就需要多继承了,而C++和Python均支持这一语言特性。

示例:

/*!
* defc
* author: fsjohnhuang
* version: 0.1.0
* blog: fsjohnhuang.cnblogs.com
* description: define class with single inheritance, multiple mixins
* sample:
*   defc('omg.JS', {
*     ctor: function(version){
*         this.ver = verison
*     },
*     author: 'Brendan Eich',
*     getAuthor: function(){ return this.author }
*   })
*   var ES5 = defc('omg.ES5', 'omg.JS', {
*        ctor: function(version){}
*   })
*   var mixins = [{isGreat: true, hasModule: function(){return true}}]
*   var ES6 = defc('omg.ES6', ES5, mixins, {
*        ctor: function(version){},
*      getAuthor: function(){
*            var author = zuper() // invoke method of super class which is the same signature
*            return [author, 'JSers']
*      }
*   })
*   var es6 = new ES6('2015')
*   var es6_copy = new ES6('2015')
*   assert.deepEquals(['Branden Eich', 'JSers'], es6.getAuthor())
*   assert.equals(true, es6.isGreat)
*   ES6._mixin({isGreat: false})
*   assert.equals(false, es6_copy.isGreat)
*
*   defc.mixin(es6, {isGreat: true})
*   assert.equals(true, es6.isGreat)
*   assert.equals(false, es6_copy.isGreat)
*/
;(function(factory){
var require = function(module){ return require[module] }
require.utils = {
isArray: function(obj){
return /Array/.test(Object.prototype.toString.call(obj))
},
isFn: function(obj){
return typeof obj === 'function'
},
isObj: function(obj){
return /Object/.test(Object.prototype.toString.call(obj))
},
isStr: function(obj){
return '' + obj === obj
},
noop: function(){}
}

factory(require, this)
}(function(require, exports){
var VERSION = '0.1.0'
var utils = require('utils')

var clazzes = {}

/**
* @method defc
* @public
* @param {DOMString} clzName - the full qualified name of class, i.e. com.fsjohnhuang.Post
* @param {Function|DOMString|Array.<Object>|Object} [zuper|mixins|members] - super class, mixin classes array or members of class
* @param {Array.<Object>|Object} [mixins|members] - mixin classes array or members of class
* @param {Object} [members] - members of class. ps: property "ctor" is the contructor of class
* @returns {Object}
*/
var defc = exports.defc = function(clzName, zuper, mixins, members){
if (clazzes[clzName]) return clazzes[clzName].ctor
var args = arguments, argCount = args.length

members = utils.isObj(args[argCount-1]) && args[argCount-1] || {}
mixins = utils.isArray(mixins) && mixins || utils.isArray(zuper) && zuper || []
zuper = utils.isFn(zuper) && zuper || utils.isStr(zuper) && clazzes[zuper] && clazzes[zuper].ctor || 0

var clz = clazzes[clzName] = {}
var ctor = clz.ctor = function(){
// execute constructor of super class
if (zuper) zuper.apply(this, arguments)
// execute constructor
members.ctor && members.ctor.apply(this, arguments)
// contruct public fields
for(var m in members)
if(utils.isFn(this[m] = members[m])) delete this[m]
}
ctor.toString = function(){ return (members.ctor || utils.noop).toString() }

// extends super class
if (zuper){
var M = function(){}
M.prototype = zuper.prototype
ctor.prototype = new M()
ctor.prototype.contructor = members.ctor || utils.noop
}

// construct public methods
for(var m in members)
if(m === 'ctor' || !utils.isFn(members[m])) continue
else if(!(zuper.prototype || zuper.constructor.prototype)[m]) ctor.prototype[m] = members[m]
else (function(m){
// operate the memebers of child within the methods of super class
var _super = function(self){ return function(){ return (zuper.prototype || zuper.constructor.prototype)[m].apply(self, arguments)} }
var fnStr = members[m].toString()
, idx = fnStr.indexOf('{') + 1
, nFnStr = fnStr.substring(0, idx) + ';var zuper = _super(this);' + fnStr.substring(idx)

eval('ctor.prototype[m] = ' + nFnStr)
}(m))

// do shallow mixins
for(var mixin in mixins)
for(var m in mixins[mixin]) ctor.prototype[m] = mixins[mixin][m]

// additional methods
ctor._mixin = function(/*...mixins*/){
var mixins = arguments
for(var mixin in mixins)
for(var m in mixins[mixin]) this.prototype[m] = mixins[mixin][m]
}

return ctor
}

/**
* @method defc.mixin
* @public
* @param {Any} obj - mixin target
* @param {...Object} mixins - mixin source
*/
defc.mixin = function(obj/*, ...mixins*/){
var mixins = Array.prototype.slice.call(arguments, 1)
for(var mixin in mixins)
for(var m in mixins[mixin]) obj[m] = mixins[mixin][m]
}
}))


View Code

Conclusion                          

后续我们将继续探讨C#和Java实现Mixin Pattern的方式,敬请期待,哈哈!

尊重原创,转载请注明来自:/article/4741163.html ^_^肥子John

Thanks                            
http://hax.iteye.com/blog/182339 http://cxyclub.cn/n/34324/ http://wiki.jikexueyuan.com/project/javascript-design-patterns/mixin.html http://www.zhihu.com/question/20778853 https://en.wikipedia.org/wiki/Mixin https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem http://codecrafter.blogspot.com/2011/03/c-mixins-with-state.html http://codecrafter.blogspot.com/2010/02/c-quasi-mixins-example.html http://stackoverflow.com/questions/6644668/mixins-with-c-sharp-4-0 http://www.sitepoint.com/ruby-mixins-2/ http://www.tutorialspoint.com/ruby/ruby_object_oriented.htm http://www.ibm.com/developerworks/cn/java/j-diag1203/ http://www.linuxjournal.com/node/4540/print
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: