Class 在TypeScript中,如何防止对派生类调用方法?
有三节课Class 在TypeScript中,如何防止对派生类调用方法?,class,typescript,subclass,derived-class,Class,Typescript,Subclass,Derived Class,有三节课 // in external library, which I don't want to modify class ComponentBase { // I want calling this to be disallowed forceUpdate() {} } class ComponentBase_MyVersion extends ComponentBase { // I want subclasses to always call this, in
// in external library, which I don't want to modify
class ComponentBase {
// I want calling this to be disallowed
forceUpdate() {}
}
class ComponentBase_MyVersion extends ComponentBase {
// I want subclasses to always call this, instead of forceUpdate()
Update() {}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// I want this to be disallowed
this.forceUpdate();
// forcing the subclass to call this instead
this.Update();
}
}
我如何才能做到这一点,只需更改ComponentBase\u MyVersion
有没有办法“隐藏”基类成员
或者是一种覆盖定义的方法——比如C#中的“new”关键字——让我破坏方法定义,至少在尝试调用它时会出现警告?我找到了一种似乎有效的方法——也就是说,当有人试图调用
forceUpdate()时会出现警告
在子类实例上
forceUpdate(_: ()=>"Do not call this. Call Update() instead.") {
throw new Error("Do not call this. Call Update() instead.");
}
现在,当我编写newmycomponent().forceUpdate()
时,我得到一个编译器错误,警告消息中包含一个说明,告诉我改用Update()
编辑:显然,这只适用于基类,因为基类已具有此定义:
forceUpdate(callBack?: () => any): void;
相反,如果基本方法最初是在没有参数的情况下定义的(如在OP中),则上述解决方案不起作用
但是,如果您有一个像我这样的案例(其中有一个这样的可选属性,您可以缩小返回类型),它可以正常工作。(不确定此返回类型缩小是错误还是有意的)通过用组合替换继承来封装实现 您可以通过在
forceUpdate
方法上添加private
access修饰符来完成此操作。这将导致所有子类无法访问forceUpdate
。但是,TypeScript不支持包访问修饰符,但可以通过用组合替换继承来实现这一点
class ComponentBase {
forceUpdate() {
}
}
class ComponentBase_MyVersion {
// Replace inheritance with composition.
private component: ComponentBase;
Update() {
this.component.forceUpdate();
}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// Now subclass can't access forceUpdate method
this.Update();
}
}
使用符号
以防止外部访问该方法。如果不想用合成替换继承,可以使用
Symbol
定义方法。如果您的目标是es5
,则必须配置tsconfig.json
compilerOptions.lib
以包括es2015.symbol
。由于每个符号
都是唯一的,因此任何外部模块都无法获取该符号并访问该方法
// libs.ts
let forceUpdate = Symbol("forceUpdate");
export class ComponentBase {
[forceUpdate]() {
}
}
export default class ComponentBase_MyVersion extends ComponentBase {
Update() {
this[forceUpdate]();
}
}
// test.ts
import ComponentBase_MyVersion from "./libs";
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// Now subclass can't access the forceUpdate method.
this.Update();
}
}
OOP不允许您执行这种方法取消。您可以像建议的那样,在类上执行此函数,但出现异常,或者使用组合: 例1:
class ComponentBase {
forceUpdate() {}
}
class ComponentBase_MyVersion extends ComponentBase {
Update() {}
forceUpdate() {
throw new Error("Do not call this. Call Update() instead.");
}
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// wil raise an exception
this.forceUpdate();
this.Update();
}
}
示例2(组成):
希望我能提供帮助。当我这样做时,我得到一个编译错误(在TypeScript 2.1.5中):“类'ComponentBase\u MyVersion'错误地扩展了基类'ComponentBase'。属性'forceUpdate'在类型'ComponentBase\u MyVersion'中是私有的,但在类型'ComponentBase'中不是。”OP说,他们只想通过对
ComponentBase\u MyVersion
@Venryx进行更改来实现这一点,您可以用composite替换继承。将ComponentBase\u MyVersion
方法委托给ComponentBase
@Venryx我找到了解决您问题的另一个解决方案,当我误读您的问题时,我更新了我的asnwer&fix答案。@holi java有趣的解决方案!在我的例子中,它不可用,因为我没有(方便的)访问权限来修改ComponentBase
类,但这对于只希望在一个类级别下可见的自定义基类很有帮助。(即,仅可由直接子类使用)要使用它,您需要在基类上更改forceUpdate()
的签名,但您不想这样做。@Diullei哦,看起来您是对的,例如OP。但是,在我的实际用例中,它是有效的,因为real forceUpdate()方法接受一个类型为()=>any
的(可选)参数。我的覆盖只是将需求缩小到()=>“random string”
——这本身不会导致错误,但会在尝试正常使用函数时显示错误。因此,上面的解决方案在一般情况下不起作用,但在我的情况下起作用。(因此,对于其他观众来说,提到这一点可能仍然很有用)很好,对于一般解决方案,按照您最初的问题,合成方法似乎是答案,但我很高兴您找到了一种处理代码的方法:)
class ComponentBase {
forceUpdate() {}
}
class ComponentBase_MyVersion {
private _component: ComponentBase = ...;
Update() {}
// expose _component desired members ...
}
class MyComponent extends ComponentBase_MyVersion {
DoSomething() {
// compilation error
this.forceUpdate();
this.Update();
}
}