[英]In TypeScript, how to prevent a method from being called on 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, 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_MyVersion
?
有沒有辦法“隱藏”基類成員?
或者也許是一種覆蓋定義的方法——就像在 C# 中使用“new”關鍵字一樣——讓我修改方法定義以至少在嘗試調用它時出現警告?
OOP 不允許您執行這種方法取消。 您可以使用您建議的 Exception 在您的班級上實現此功能,或者使用組合: https ://en.wikipedia.org/wiki/Composition_over_inheritance
示例 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(組成):
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();
}
}
我希望我有所幫助。
通過用組合委托模式替換繼承來封裝實現
您可以通過在forceUpdate
方法上添加private
訪問修飾符來做到這一點。 這將導致所有子類無法訪問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
以防止外部訪問該方法。
如果不想用組合代替繼承,可以使用Symbol
來定義方法。 如果您的目標是es5
,則必須配置tsconfig.json
compilerOptions.lib
以包含es2015.symbol
。 因為每個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();
}
}
我找到了一種似乎有效的方法——也就是說,當有人試圖在子類實例上調用forceUpdate()
時,它會導致出現警告。
forceUpdate(_: ()=>"Do not call this. Call Update() instead.") {
throw new Error("Do not call this. Call Update() instead.");
}
現在,當我編寫new MyComponent().forceUpdate()
,我收到一個編譯器錯誤,警告消息包含一個說明,告訴我改用Update()
。
編輯:顯然這只是因為基類已經有了這個定義才有效:
forceUpdate(callBack?: () => any): void;
相反,如果最初定義的基本方法沒有參數(如在 OP 中),則上述解決方案不起作用。
但是,如果您有像我這樣的案例(其中有一個類似的可選屬性,您可以縮小其返回類型),它可以正常工作。 (不確定這種返回類型縮小是錯誤還是有意為之)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.