Страницы

Поиск по вопросам

пятница, 12 июля 2019 г.

Наследование или добавление type поля?

В каких случаях вы бы стали наследовать класс, а в каких внедряли бы поле тип объекта?
Например: "Импульсный" и "Цифровой" счетчик различаются по набору полей. "Водяной счетчик" может быть как цифровым так и импульсным.
Однако чтоб получить "Водяной счетчик".data я должен поработать с полями импульсного счетчика или цифрового или интегрированного или... или ..
Напрашивается что-то вроде поля type в "Счетчик" тогда в коде можно оперировать с такими данными через switch, что сократит количество кода. Но тогда где определять эти "дополнительные" поля..
Постарался отобразить в коде суть вопроса.
// TypeScript not works on stackoverflow. // Первый пример abstract class Counter { constructor(protected serialNumber: string) {} getData(data: number): number { return data; }; } class ImpulseCounter extends Counter { constructor( private initCounter: number, private multipler: number, serialNumber, ) { super(serialNumber) } getData(data) { this.initCounter + this.multipler * data; } } class WaterImpulseCounter extends ImpulseCounter { constructor( private hot: boolean, initCounter, multipler, serialNumber ) { super(initCounter, multipler, serialNumber); } getData(data) { if (this.hot) { return this.super.getData(data) * 0.1 } else { return this.super.getData(data) } } } class DigitalCounter extends Counter { constructor( private address: string, serialNumber ) { super(serialNumber) } getData() { this.super.getData(); } } class WaterDigitalCounter extends DigitalCounter { constructor(private hot: boolean, address, serialNumber ) { super(address, serialNumber) } getData(data) { // Дублирование кода, тупик. if (this.hot) { return this.super.getData(data) * 0.1 } else { return this.super.getData(data) } } } // Второй пример enum DataTypes = { Impulse, Digital } abstract class Counter { constructor( protected serialNumber: string, protected dataType: DataTypes ) {} getData(data) { switch (this.dataType) { // В каком месте(классе) нужно определять switch логику и поля this.initCounter, this.multipler case (DataTypes.Impulse): { return this.initCounter + this.multipler * data; } } return data; }; } class WaterCounter extends Counter { hot: false; constructor( serialNumber, dataType: DataTypes ) { super(serialNumber, dataType) } getData(data) { if (this.hot) { return this.super.getData(data) * 0.1 } else { return this.super.getData(data) } } }


Ответ

Например: "Импульсный" и "Цифровой" счетчик различаются по набору полей. "Водяной счетчик" может быть как цифровым так и импульсным.
Пока это описание хрестоматийной мотивации использовать паттерн «Декоратор»:
class WaterCounter extends Counter { constructor( private impl: *Counter hot: bool serialNumber, ) { super(serialNumber) } getData(data: number): number { data=impl->data; return this.hot ? data * 0.1 : data; }; }
//...
waterImpulseCounter = new WaterCounter(new ImpulseCoubter(..., 0), hot, serial); digitalImpulseCounter = new WaterCounter(new DigitalCoubter(..., 0), hot, serial);
Но тут во-первых непонятно, что делать с серийником внутренних классов, а во-вторых немного страдает логика поведения: теперь возможно создать водный счётчик, который может использовать другой водный счётчик, так что помня основное правило, надо отделить реализацию от интерфейса; в итоге получится столь же хрестоматийный «мост»:
abstract class CounterImpl { constructor() {}
getData(data: number): number { return data; }; }
class ImpulseCounter extends CounterImpl { constructor( private initCounter: number, private multipler: number, ) { }
getData(data) { this.initCounter + this.multipler * data; } }
class DigitalCounter extends CounterImpl { constructor( private address: string, ) { }
getData() { this.super.getData(); } }
abstract class Counter { constructor(protected serialNumber: string private impl: *CounterImpl ) { }
getData(data: number): number { return impl->getData(data); }; }
class WaterCounter extends Counter { constructor( hot: bool serialNumber, ) { super(impl, serialNumber) } getData(data: number): number { return this.super.getData(data) * (this.hot ? 0.1 : 1); }; }

Комментариев нет:

Отправить комментарий