Typescript, как избежать дублирования кода в конструкторе? - PullRequest
0 голосов
/ 08 июня 2019

Рассмотрим этот класс, который используется в качестве модели данных в сценарии Model-View-Controller (я использую TypeScript 3.5):

export class ViewSource {
    private viewName : string;
    private viewStruct : IViewStruct;
    private rows : any[];
    private rowIndex : number|null;

    constructor(viewName : string) {
        // Same as this.setViewName(viewName);
        this.viewName = viewName;
        this.viewStruct = api.meta.get_view_struct(viewName);
        if (!this.viewStruct) {
            throw new Error("Clould not load structure for view, name=" + (viewName));
        }
        this.rows = [];        
        this.rowIndex = null;
    }

    public setViewName = (viewName: string) => {
        this.viewName = viewName;
        this.viewStruct = api.meta.get_view_struct(viewName);
        if (!this.viewStruct) {
            throw new Error("Clould not load structure for view, name=" + (viewName));
        }
        this.rows = [];        
        this.rowIndex = null;
    }

    public getViewStruct = ():IViewStruct => { return this.viewStruct; }

    public getCellValue = (rowIndex: number, columnName: string) : any => {
        const row = this.rows[rowIndex] as any;
        return row[columnName];
    }

}

Это не полный класс, я только включил несколько методов, чтобы продемонстрировать проблему. ViewSource является изменяемым объектом. На него можно ссылаться из нескольких частей приложения. (Обратите внимание, что изменчивый объект - это факт. Этот вопрос не касается выбора другой модели данных, в которой используются неизменяемые объекты.)

Всякий раз, когда я хочу изменить состояние объекта ViewSource, я вызываю его метод setViewName. Это работает, но это также очень неуклюже. Каждая строка кода в конструкторе повторяется в методе setViewName.

Конечно, невозможно использовать этот конструктор:

constructor(viewName : string) {
    this.setViewName(viewName);
}

, поскольку это приводит к ошибке TS2564:

Property 'viewStruct' has no initializer and is not definitely assigned in the constructor.ts(2564)

Я не хочу игнорировать ошибки TS2564 в целом. Но я также не хочу повторять все инициализации атрибута. У меня есть некоторые другие классы с еще большим количеством свойств (> 10), и соответствующее дублирование кода выглядит некрасиво, и это подвержено ошибкам. (Я мог бы забыть, что некоторые вещи должны быть изменены двумя способами ...)

Так, как я могу избежать дублирования многих строк кода?

1 Ответ

1 голос
/ 08 июня 2019

Я думаю, что лучший способ избежать дублирования кода в этом случае - создать функцию, содержащую код инициализации, но вместо установки значения она возвращает значение, которое необходимо установить.
Что-то вродеследующее:

export class ViewSource {
    private viewName : string;
    private viewStruct : IViewStruct;
    private rows : any[];
    private rowIndex : number|null;

    constructor(viewName : string) {
        const {newViewName, newViewStruct, newRows, newRowIndex} = this.getNewValues(viewName);
        this.viewName = newViewName;
        this.newViewStruct = newViewStruct;
        // Rest of initialization goes here
    }

    public setViewName = (viewName: string) => {
        const {newViewName, newViewStruct, newRows, newRowIndex} = this.getNewValues(viewName);
        // Rest of initialization goes here
    }

    privat getNewValues = (viewName) => {
        const newViewName = viewName;
        const newViewStruct = api.meta.get_view_struct(viewName);
        if (!newViewStruct) {
            throw new Error("Clould not load structure for view, name=" + (viewName));
        }
        const newRows = [];        
        const newRowIndex = null;
        return {newViewName, newViewStruct, newRows, newRowIndex};
    }

}

Таким образом, единственное, что вы дублируете, это установка значений, а не их вычисление, и если вычисления значений станут более сложными, вы можете просто расширить возвращаемое значение.

...