【问题标题】:How should I properly use parent class methods and the keyword extends in typescript?我应该如何正确使用父类方法和打字稿中的关键字扩展?
【发布时间】:2018-05-05 18:28:31
【问题描述】:

我有两个类,一个是父类,一个是子类,它们实现类型以定义其预期功能。就在下面。

export abstract class BaseLogService implements IBaseLogService
{
    static $inject: string[] = ['$http']
    constructor(private $http:ng.IHttpService){

    }

    baseMethod1 = (objToLog): void => {
        //do stuff
    }

    baseMethod2 = (objToLog): void => {
        //do stuff
    }
}


class LocalLogService extends BaseLogService implements ILocalLogService
{
    constructor(private $http:ng.IHttpService){
        super(this.$http);
    }

    localMethod1 = (): void => {
        //do stuff
    }

}

export interface IBaseLogService {
    baseMethod1(objToLog):void;


    baseMethod2(objToLog):void;
}

export interface ILocalLogService extends IBaseLogService{
    localMethod1(): void;
}

该应用程序使用日志服务,并为不同的公司记录事情。对于 A 公司,与 B 和 C 公司相比,它可能会记录一些不同的内容。这就是每个公司都有本地日志服务的原因。但是所有公司都记录了一些通用的东西。所以这就是为什么有一个本地实现扩展的通用 Log 类的原因。

介绍完我的问题是,如何适当地利用我的父类的方法?

为了扩展这一点,让我解释一下这一切是如何使用的。这是 angularjs,所以在应用程序其他地方的控制器中有一个 api POST 调用。

在 .then() 中该调用的承诺返回时,需要执行 baseMethod1 以记录一些常见内容。所以它就像下面的伪代码

myThingToAdd: any;

static $inject: string[] = ['localLogService']

constructor(private localLogService: ILocalLogService){}

this.myPOSTApi.addAThing(this.myThingToAdd)
    .then((POSTResponse) => {
        this.localLogService.baseMethod1(POSTResponse);
    });

这就是我的困惑发挥作用的地方。当调用 baseMethod1 时,我有一些公司特定的事情需要发生。但是因为我的服务调用直接从控制器转到父类,所以我跳过了需要发生本地逻辑的本地子服务。

我可以设置它,以便我的 .then() 服务调用转到我的本地子类,它在调用 super.baseMethod1() 之前执行我公司特定的逻辑,但考虑到我能够调用父类的方法直接来自我在控制器中注入的服务。

然后我想,我可以进行两个调用,一个用于本地逻辑,一个用于公共,每个调用各自的服务,但这对我来说似乎没有优化。并且感觉它违背了继承的目的。

然后我走下兔子洞,想通了我现在的位置。

我的父类方法是否应该对应用程序的其余部分不可见,并且只能在我的子类中使用?如果是这样,混淆应该有多深?如果我的子类有公开公开的方法,直接调用 super.baseMethod1() 就像

localMethod1 = () => {
    //local logic
    super.BaseMethod1();
}

还是说太直接了?我应该有一个公开的子方法,然后调用一个调用我的超级方法的私有内部方法吗?喜欢

localMethod1 = () => {
    //local logic
    this.callSuperMethod1();
}

private callSuperMethod1 = () => {
    super.baseMethod1();
}

我认为我严重过度考虑了继承和封装的想法,并且希望就如何继续并在务实的正确做法和高效/优化的代码之间取得平衡的一些建议。

【问题讨论】:

  • 我添加了一个答案。无法解决某些问题,我的父类方法是否不可见...等。这总是特定于特定情况,而问题和代码非常抽象。

标签: angularjs typescript inheritance wrapper encapsulation


【解决方案1】:

继承正是这个问题应该解决的方式:

我可以设置它,以便我的 .then() 服务调用转到我的本地子类,它在调用 super.baseMethod1() 之前执行我公司特定的逻辑,但考虑到我能够调用父类的方法直接来自我在控制器中注入的服务。

子类可以实现自己的baseMethod1,也可以通过super 方法调用应用父类的行为。正如this answer 中所解释的,继承是不应使用实例箭头方法的少数原因之一。这不起作用,因为实例方法无权访问super

localMethod1 = () => {
    //local logic
    super.BaseMethod1();
}

它是:

export abstract class BaseLogService {
    ...
    constructor(protected $http:ng.IHttpService) {}

    baseMethod1(objToLog): void {
        //do stuff
    }
    ...
}

class LocalLogService extends BaseLogService {
    // can be omitted
    constructor($http:ng.IHttpService){
        super($http);
    }

    baseMethod1(objToLog): void {
        super.baseMethod1(objToLog)
        //do stuff
    }
}

如果ILocalLogService 完全复制公共BaseLogService 接口,则它是多余的-BaseLogService 可以用作接口。 $http 应该是 protected 而不是 private,因为它可能用于子类。可见性修饰符只能在父构造函数中指定一次。如果子构造函数除了调用super之外什么都不做,可以省略。

由于一次只应该使用一个记录器类,这就是 DI 模式的用途。这可以单独使用 AngularJS DI 来解决:

// company A module
app.service('logger', ALogService);

使用服务的单元不应该知道他们正在使用哪个实现:

FooController {
  constructor(public logger: BaseLogService) {}
}

【讨论】:

  • 感谢您的这篇文章,这对您有很大帮助!我肯定对如何使用它有了更好的感觉!
  • 很高兴它有帮助。
猜你喜欢
  • 2017-09-22
  • 2019-06-27
  • 2022-10-13
  • 2020-07-07
  • 2017-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-11
相关资源
最近更新 更多