Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 重构基于mixin的遗留类层次结构_Javascript_Design Patterns_Traits_Mixins_Composition - Fatal编程技术网

Javascript 重构基于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

我目前正在从事一个巨大的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.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几乎是不可能的
我正在寻找更好的类似插件的替代方案,它允许按照以下要求逐步重构所有现有的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