Как правильно использовать методы родительского класса и ключевое слово расширяется в машинописи? - PullRequest
0 голосов
/ 05 мая 2018

У меня есть два класса, один родительский и один дочерний, которые реализуют типы для определения их ожидаемой функциональности. Это ниже здесь.

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();
}

Я думаю, что я серьезно переосмысливаю идеи наследования и инкапсуляции, и был бы признателен за некоторые советы о том, как действовать и найти баланс между прагматичными правильными практиками и эффективным / оптимизированным кодом.

1 Ответ

0 голосов
/ 05 мая 2018

Наследование - это способ решения этой проблемы:

Я мог бы настроить его так, чтобы мой вызов службы .then () передавался в мой локальный дочерний класс, который выполняет специфическую для моей компании логику перед вызовом super.baseMethod1 (), но это кажется очень косвенным, учитывая, что я могу вызвать метод родительского класса прямо из моего внедренного сервиса в контроллере.

Дочерний класс может реализовывать свой собственный baseMethod1, а также может применять поведение от родителя с помощью вызова метода super. Как объяснено в этом ответе , наследование является одной из немногих причин, по которой методы стрелки экземпляра не должны использоваться. Это не будет работать, потому что метод экземпляра не имеет доступа к 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) {}
}
...