题记
大家写项目的时候会不会经常遇到这么一个问题。
B Class 和 B2 Class分别继承至 A Class 和A2 Class,但是因为B和B2又希望有共同的一些方法和属性。请问大家一般怎么扩展这个结构?
可能大家会想,那还不简单,A Class和 A2 Class共同在继承一个 Super A Class就好了。对,这样是可以的,可问题是,如果这个A Class和A2 Class不是项目中的,而是依附于的第三方依赖,又或者它们就是出于某些原因,你无法去改变A和A2的继承链和数据结构,你又如何是好?
那要不退而求其次?让B和B2里面用一个属性去连接到C?但是那样的话调用链就变成了 B.C.xxx()了。暂且不说使用上好不好使吧,如果你想要覆盖C的某个方法的实现,你又该如何是好?
可能还有朋友通过装饰器来实现,但是装饰器实现后的代码提示相关的可真是不好使呀。
基于上述问题,我分享个小经验给大家.
实现
基于TypeScript的mixin来实现。
我们将C Class变成一个mixin函数,然后通过泛型约束来设置可以混入进A和A2.
type AConstructor = new (...args: any[]) => A
type A2Constructor = new (...args: any[]) => A2
export function CClass<
T extends AConstructor | A2Constructor
>(base: T){
return class CClass extends base {
/** 在这里就可以为C class 添加特定的扩展函数或者属性了 */
name:string
age:number
getAge(){
return 18;
}
get name(){
return "Hello";
}
}
}
然后,我们在B和B2的继承那进行简单的修改。
//原版====>
class B extends A{
...
}
/// 修正为==>
class B extends CClass(A){
...
}
然后就可以愉快的使用B的调用在C上面扩展的函数和方法啦~
遗留问题
通过mixin这样实现后,CClass中没法设置private变量可怎么处理?
方案一:
export function CClass<
T extends AConstructor | A2Constructor
>(base: T){
// 在这里定义一些私有变量使用
//---BEGIN
const name:string = 'Hello';
//----END
return class CClass extends base {
/** 在这里就可以为C class 添加特定的扩展函数或者属性了 */
name:string
age:number
getAge(){
return 18;
}
get name()=>name;
}
}
方案二
使用 # 修饰符在属性和方法前面。这样也可以将属性和函数声明为私有的。
export function CClass<
T extends AConstructor | A2Constructor
>(base: T){
return class CClass extends base {
//私有变量
#name:string
//私有方法
get #name()=> #name;
}
}
PS
最后如果大家有什么好的建议,还请不吝赐教😋
Bye~