【问题标题】:How to block TypeScript class property or method multi-level inheritance?如何阻止 TypeScript 类属性或方法的多级继承?
【发布时间】:2019-08-01 18:50:19
【问题描述】:

这是下一个 JavaScript 类结构:

// data.service.ts
export class DataService {
   public url = environment.url;

   constructor(
       private uri: string,
       private httpClient: HttpClient,
   ) { }

   getAll() {}

   getOne(id: number) {}

   create(data: any) {}

   // etc...
}

接下来是可以使用DataService的方法与服务器通信的通用数据模型:

// Model.model.ts
import './data.service';

export class Model extends DataService {
    all() {}

    get() {
        // parse and make some basic validation on the
        // DataService.getOne() JSON result
    }

    // etc...
}

最后我基于 Model.model.ts 创建了一个特定的数据模型:

// User.model.ts
import './Model.model.ts';

export class User extends Model {
    id: number;
    name: string;
    email: string;

    init() {
        // make specific validation on Model.get() result
    }
}

如果我在我的代码中使用 User 类,我可以根据需要直接调用 DataService 的 getAll() 函数。但这不是一件好事,因为在这种情况下我错过了内置验证。

如何阻止类的方法继承?

我正在寻找类似 PHP 的 static 方法的东西。子类可以使用方法,但他的子类不能。

我想要这样的东西:

const dataService = new DataService();
dataService.getAll(); // void

const model = new Model();
model.getAll(); // undefined
model.all();    // void

const user = new User();
user.getAll();  // undefined
user.all();     // void

有什么办法吗?

【问题讨论】:

  • 我猜你需要privateprotected
  • 从概念上讲,模型不是 DataService 并对其进行建模对我来说似乎是完全错误的。也许一个可能需要另一个,但它们不应该是同一件事。
  • 不是,但是Model可以有get()方法,可以从服务器获取数据,然后自己初始化。在这种情况下,我可以使用user.get(1) 来获取数据,并将它们初始化到用户模型中。当然,user.get() 方法期望来自 API 的 JSON 看起来像一个用户模型,但可能包含 0null'' 值。 user.init() 可以处理这些,最后我得到一个有效的用户模型。当然,我为客户、产品、文档、案例文件等使用了许多模型……每个模型都需要一个 .get() 方法和一个特定的 .init() 方法才能有用。

标签: javascript typescript class inheritance multiple-inheritance


【解决方案1】:

您可以通过在函数private getAll() {} 中添加private 关键字来阻止它构建。但是private 是 TypeScript 功能,而不是 Javascript,所以如果你强制构建它,它仍然是可调用的。此刻没有办法完全阻止它。

因此,如果您希望在 TypeScript 中阻止它,只需在此处添加 private 关键字即可。但它是不可构建的,不会像您期望的那样返回 undefined。否则,只需将函数替换为子类上未定义返回的函数

【讨论】:

    【解决方案2】:

    使用所示的代码和所述的用例,获得所需行为的唯一方法是根本不使 Model 扩展 DataService。有一个subsitution principle 表示如果Model extends DataService,那么某人应该能够像对待DataService 实例一样对待Model 实例。事实上,如果ModelDataService 的特殊类型,并且有人请求DataService 实例,您应该可以给他们Model。你告诉他们他们不能在上面调用getAll() 方法是不公平的。所以继承树不能按照你的方式工作。相反,您可以这样做:

    // ultimate parent class of both DataService and Model/User 
    class BaseDataService {
      getOne(id: number) { }
      create(data: any) { }
      // etc...
    }
    
    // subclass with getAll()
    class DataService extends BaseDataService {
      getAll() {}
    }
    
    
    // subclass without getAll()
    class Model extends BaseDataService {
      all() { }
      get() { }
      // etc...
    }
    
    class User extends Model {
      id!: number;
      name!: string;
      email!: string;
      init() { }
    }
    
    const dataService = new DataService();
    dataService.getAll(); // void
    
    const model = new Model();
    model.getAll(); // error
    model.all();    // okay
    
    const user = new User();
    user.getAll();  // error
    user.all();     // okay
    

    这与您指定的完全一样。完美,对吧?


    好吧,我有一种下沉的感觉,你会尝试这个并且因为你不能在ModelUser实现 中调用this.getAll() 感到不安......可能在可疑的内部-Modelall() 方法的空主体。我已经有了防御性地指向Minimum, Complete, and Verifiable Example 文章的冲动,因为问题如上所述似乎不需要这样做。

    如果您确实需要,您仍然不能违反替代原则。相反,我建议将getAll() 设为protected 方法,并在DataService 上公开all() 方法:

    class DataService {
      getOne(id: number) { }
      create(data: any) { }
      protected getAll() { }
      all() { 
        this.getAll();
      }
      // etc...
    }
    
    class Model extends DataService {
      all() {
        this.getAll();
      }
      get() { }
      // etc...
    }
    
    class User extends Model {
      id!: number;
      name!: string;
      email!: string;
      init() { }
    }
    
    const dataService = new DataService();
    dataService.getAll(); // error
    dataService.all(); // okay
    
    const model = new Model();
    model.getAll(); // error
    model.all();    // okay
    
    const user = new User();
    user.getAll();  // error
    user.all();     // okay
    

    并接受getAll() 是一种纯粹的内部方法永远不会看到光明的事实。

    好的,希望其中之一有所帮助;祝你好运!

    【讨论】:

      猜你喜欢
      • 2015-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多