【问题标题】:Cannot create an AngularJS service made of a class that inherits from multiple classes无法创建由从多个类继承的类组成的 AngularJS 服务
【发布时间】:2018-01-08 08:05:43
【问题描述】:

背景:我正在开发一个将自身与一些 AWS 服务集成的 Angular 1.x 项目。我为我使用的每个 DynamoDB 表提供了一项服务,用于管理基本操作,如 put、query、get、update 等。然后将这些服务导入“主”服务中,该服务添加了一些更复杂的功能(如从一个表并插入另一个表)。在表类中,我有两个“私有”函数(我认识它们,因为它们都以“_”开头)和公共。一般服务使用两者。每个服务都有 ES6 类语法,所以我的表类将如下所示:

export default class {
    constructor(some, var, and, const) {
        this.some = some;
        this.var = var;
        this.and = and;
        this.const = const;
        ...
    }

    _myPrivateMethod() {
        console.log(`I'm private!`);
    }

    myPublicMethod() {
        console.log(`I'm public!`);
    }
}

问题:我希望能够只将主要服务导出到我的 Angular 控制器中,而不是所有“表”服务,所以我的目标是实现多类继承,其中我的主要服务继承自所有表服务并公开了它们的所有方法(公共和私有,我不在乎),因此我只导入我的主要服务并拥有我需要的一切。

我找到的一些解决方案:我在这里阅读了一些类似的问题,但没有一个答案适合我的情况,因为我需要将不同的变量传递给我的表服务的构造函数。我不想使用任何使多重继承更容易的外部库,因为项目会很大而且我不想继续添加东西,所以我想自己实现它。
我的最佳想法是创建子类的实例,使用Object.getPrototypeOf 获取它们的原型,并通过Object.assignthis 的原型设置为Object.setPrototypeOf 与所有它们,如下所示:

import TableClass1 from './tables/1';
import TableClass2 from './tables/2';

export default class MyMainClass {
    constructor(some, var, other, param) {
        let myTableInstance1 = new TableClass1(some, var);
        let myTableInstance2 = new TableClass2(other, param);
        let tmpMultiInherit = Object.assign({}, Object.getPrototypeOf(myTableInstance1), Object.getPrototypeOf(myTableInstance2));

        Object.setPrototypeOf(this, tmpMultiInherit);
    }
}

这对我来说似乎是个好主意,因为 getPrototypeOf(s) 函数返回的正是我需要在 typeof object 中添加到我的类的内容,但 Object.assign 行返回 {},我不能明白为什么。

This 问题是我发现的最有用的问题,但没有一个答案能解释如何使用不同父类的构造函数形式实现多继承。

因此,如果你们中的任何人知道为什么此方法失败或过去曾遇到过此问题,我将非常感谢您的帮助。

提前谢谢你!

【问题讨论】:

    标签: javascript angularjs inheritance


    【解决方案1】:

    为什么首先需要多重继承?几乎所有的问题都可以在没有继承的情况下得到更好的解决,而且绝对没有多重继承带来的麻烦。

    在这种情况下,为什么不创建一个由这些表类组合的服务,而不是从所有表类继承(组合优于继承)?

    import TableClass1 from './tables/1';
    import TableClass2 from './tables/2';
    
    export default class MyMainClass {
        constructor(some, var, other, param) {
            this.table1 = new TableClass1(some, var);
            this.table2 = new TableClass2(other, param);
        }
    }
    

    它更易于编写、更易于调试和更易于测试。特别是如果不是在构造函数中创建 new TableClass1 实例,而是通过依赖注入传递它们。


    至于为什么您的“多重继承”解决方案不起作用:Object.assign 调用仅复制原型中的字段,而不是对象本身上设置的字段。它也不会沿着原型链上升,因此它也不会从父类中复制任何东西。一个普通的for (prop in obj) 循环应该有助于捕获所有内容。

    您仍然必须非常小心,因为任何捕获的this 指针仍将指向原始myTableInstance1myTableInstance2 对象,并最终以非常不明显的方式做错事。总的来说,这听起来像是一种难以发现的微妙错误的来源,我强烈建议不要使用这种方法。

    【讨论】:

    • 感谢托马斯的回复。我知道多重继承通常不好,但您的解决方案意味着如果我需要从我的控制器访问 TableClass1 中的方法,我必须写MyMainService.table1.method()。我宁愿只写MyMainService.method()(当然知道method 这个名字在我的主类继承的所有类中都是唯一的)。另一方面,我不想在 MyMainClass 中创建一个只调用 TableClass1 中相同方法的方法,因为它们可能会按数量增长。
    • 我会坚持使用MyMainService.table1.method(),或者更好的是,直接注入TableClass1 实例。后者更符合“只使用你使用的东西”的指导方针,并且还将提高可测试性,因为你不需要模拟整个MyMainService
    • 在将我的代码更改为您建议的内容之前,我已尝试将我的 tmpMultiInherit 值更改为 Object.assign({}, myTableInstance1, myTableInstance2),就像您在回答中所说的那样,但它只是复制属性,而不是方法,这是我需要的。这不是很奇怪吗?我的实例在原型中有它们的方法,所以Object.assign 应该将它们复制到 tmpMultiInherit 中,对吧?我在这里创建了一个 JSFiddle:jsfiddle.net/6w5vjg7b。如您所见,multiInherit.method1(); 不起作用并抛出错误“TypeError: multiInherit.method1 is not a function”
    • 对不起,我忘了Object.assign 只复制对象自己的属性,并没有遍历原型链。常规的 for (prop in obj) { ... } 循环应该会更好。
    • Mmmmm 与 for 循环的结果相同,但如果我在构造函数中使用 this.method = function() { ... } 定义我的方法,它就可以工作。我已经更新了代码:jsfiddle.net/6w5vjg7b/2。唯一打印出来的方法是testMethod,这是在构造函数中创建的唯一方法,因此它被复制到 multiInherit 中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-19
    • 1970-01-01
    相关资源
    最近更新 更多