Javascript 重构基于mixin的遗留类层次结构
我目前正在从事一个巨大的javascript项目,该项目有一个巨大的类层次结构,并大量使用mixin来扩展基类的功能。下面是一个mixin的示例,我们使用它创建类对象:Javascript 重构基于mixin的遗留类层次结构,javascript,design-patterns,traits,mixins,composition,Javascript,Design Patterns,Traits,Mixins,Composition,我目前正在从事一个巨大的javascript项目,该项目有一个巨大的类层次结构,并大量使用mixin来扩展基类的功能。下面是一个mixin的示例,我们使用它创建类对象: // Base.js var Base = compose({ setX: function (x) { this.x = x; }, setY: function (y) { this.y = y; }, setPosition: function (x, y) { this.s
// Base.js
var Base = compose({
setX: function (x) {
this.x = x;
},
setY: function (y) {
this.y = y;
},
setPosition: function (x, y) {
this.setX(x);
this.setY(y);
}
})
// SameXAndY.js - mixin
var SameXAndY = compose({
// Executes after setX in Base.js
setX: compose.after(function (x) {
this.y = x;
}),
// Executes after setY in Base.js
setY: compose.after(function (y) {
this.x = y;
}),
// Overrides setPosition in Base.js
setPosition: compose.around(function (base) {
return function (x, y) {
if (x !== y) {
throw 'x !== y';
}
return base.call(this, x, y);
}
})
})
此解决方案存在以下问题:
- mixin之间相互依赖性很强——您可以通过改变mixin在基类中的顺序来破坏某些东西
- 没有简单的方法可以确保在类中安全地包含一些mixin,您可能需要实现额外的方法/在其中包含额外的mixin
- 由于各种混合,子类有数百个方法
- 在Flow或Typescript中重写mixin几乎是不可能的
- 能够明确描述所有依赖项(即以某种方式描述
需要PluginA
和PluginB
)PluginC
- 插件不应该用它的方法污染目标类
- 它们应该能够以某种方式拦截基类逻辑(如在
中)SameXAndY
- 插件应该是普通的js类
Vladimir.我重构了OP的示例,它实现了要求的功能。 如果我有什么不对劲,请告诉我
类BaseXYType{
构造函数(stateValue){//注入的状态对象。
this.setX=函数setX(x){
返回(stateValue.x=x);
};
this.setY=函数setY(y){
返回(stateValue.y=y);
};
Object.defineProperty(这个“x”{
get:函数getX(){
返回stateValue.x;
},
可枚举:true
});
Object.defineProperty(这个“y”{
get:函数getY(){
返回stateValue.y;
},
可枚举:true
});
Object.defineProperty(这是“valueOf”{
值:函数值(){
返回Object.assign({},stateValue);
}
});
Object.defineProperty(这是“toString”{
值:函数toString(){
返回JSON.stringify(stateValue);
}
});
}
setPosition(x,y){//原型方法。
这是setX(x);
这是赛蒂(y);
返回此.valueOf();
}
}
类SameXYType扩展了BaseXYType{
//-JavaScript中的特征应该是
//只是特性和对象组合规则的容器
//独占将在特征的应用时间执行。
构造函数(stateValue){//注入的状态对象。
超级(状态值);
调用(this,stateValue);
}
}
var with sameInternalXandyState=Trait.create(函数(使用,涂抹器){
//本地函数以启用共享代码,从而实现更少的内存消耗。
//
returningStateChangeXHandler(returnValue、argsArray、payloadList)后的函数{
变量
stateValue=payloadList[0];
stateValue.y=argsArray[0];//与x的y相同。
}
returningStateChangeHandler(returnValue、argsArray、payloadList)后的函数{
变量
stateValue=payloadList[0];
stateValue.x=argsArray[0];//与y的x相同。
}
函数setPositionInterceptor(proceedSetPosition、interceptor、argsArray、payloadList){
变量
x=argsArray[0],
y=argsArray[1];
如果(x!==y){
抛出(新类型错误([x,”!==”,y]。联接(“”));
}
return proceedSetPosition.call(this,x,y);
}
涂抹器(功能sameXAndYBehavior(状态值){
//施药器内无其他特征特定行为
}).需要([
“setX”,
“赛蒂”,
“设置位置”
]).返回后(
“setX”,返回StateChangeXHandler后
).返回后(
“塞蒂”,返回州政府后
).周围(
“设置位置”,设置位置拦截器
);
});
变量
base_1=新的BaseXYType({x:7,y:11}),
base_2=新的BaseXYType({x:99,y:1}),
same_1=新的SameXYType({x:13,y:5}),
same_2=新的SameXYType({x:99,y:1});
log(‘(‘+base_1):’,(‘+base_1));
log(‘(‘+base_2):’,(‘+base_2));
log(“(“+same_1):”,(“+same_1));
log(“(“+same_2:”,(“+same_2));
log('base_1.valueOf():',base_1.valueOf());
log('base_2.valueOf():',base_2.valueOf());
log('same_1.valueOf():',same_1.valueOf());
log('same_2.valueOf():',same_2.valueOf());
log('base_1.x:',base_1.x.);
log('(base_1.x=“foo”):',(base_1.x=“foo”);
log('base_1.x:',base_1.x.);
log('base_1.y:',base_1.y.);
log('(base_1.y=“bar”):',(base_1.y=“bar”);
log('base_1.y:',base_1.y.);
log('same_2.x:',same_2.x.);
log('(same_2.x=“biz”):',(same_2.x=“biz”);
log('same_2.x:',same_2.x.);
log('same_2.y:',same_2.y.);
log('(same_2.y=“baz”):',(same_2.y=“baz”);
log('same_2.y:',same_2.y.);
console.log('base_1.setY(“foo”):'、base_1.setY(“foo”));
log('base_1.y:',base_1.y.);
console.log('base_2.setX(“bar”):'、base_2.setX(“bar”));
log('base_2.x:',base_2.x.);
console.log('base_1.setPosition(“brown”、“fox”):'、base_1.setPosition(“brown”、“fox”));
log(‘(‘+base_1):’,(‘+base_1));
log('base_2.setPosition(“lazy”,“dog”):'、base_2.setPosition(“lazy”,“dog”));
log(‘(‘+base_2):’,(‘+base_2));
console.log('same_1.setY(543):',same_1.setY(543));
log('same_1.x:',same_1.x.);
log('same_1.y:',same_1.y.);
log('same_1.valueOf():',same_1.valueOf());
console.log('same_2.setY(79):',same_2.set