使用 TypeScript 实现面向对象设计的惯用方法

问题描述 投票:0回答:1

假设我用面向对象语言(例如Python)实现了以下设计。我知道 OO 方式有点不自然,有时在使用 TypeScript 时不是首选。那么在 TypeScript 中实现相同设计的惯用方法是什么?

想法是:

  • 我有一个
    Car
    类型来描述通用汽车。
  • 对于所有手动变速箱汽车,我可以提供一个抽象类:
    • 按照启动手动变速箱汽车的经典步骤实施
      Car
      类型,并且
    • 提供一些hook抽象方法供子类实现,并且
    • 提供一些默认impl的方法,以便子类可以选择重用或重写。
  • 对于其他类型的汽车,我可以自由地以不同的方式实现
    Car
    类型。

这将是 Python 代码:

from abc import ABC, abstractmethod
import json

class Car(ABC):
    @abstractmethod
    def start(self):
        raise NotImplemented

class ManualGearboxCar(Car):
    def start(self):
        self.engage_clutch()
        self.start_engine()
        
        dashboard_info = self.read_dashboard()
        print("Dashboard:", json.dumps(dashboard_info))
        # ... Check dashboard_info and raise if anything goes wrong ...
        if not dashboard_info["ok"]:
            raise Exception("Something is not OK")

        self.shift_gear(1)
        self.release_clutch()
        print("Car started!")

    def read_dashboard(self) -> dict:
        return {
            "foo": "bar",
            "default": "values",
            "ok": True,
        }

    def engage_clutch(self):
        print("[DefaultClutch] engaged!")

    def release_clutch(self):
        print("[DefaultClutch] released!")

    @abstractmethod
    def start_engine(self):
        raise NotImplemented

    @abstractmethod
    def shift_gear(self, level: int):
        raise NotImplemented

class Picasso(ManualGearboxCar):
    def read_dashboard(self) -> dict:
        info = super().read_dashboard()
        return info | {
            "brand": "Citroen",
        }

    def start_engine(self):
        print("[Picasso] engine started!")

    def shift_gear(self, level: int):
        print("[Picasso] gear shifted to:", level)


class Tesla(Car):
    def start(self):
        print("[Tesla] Wow it just starts!")

if __name__ == "__main__":
    picasso = Picasso()
    picasso.start()

    tesla = Tesla()
    tesla.start()

这是我在 TypeScript 中实现相同功能的想法,但我觉得它有点奇怪,而且不是原生的......

type Car = {
  start(): void;
}

abstract class ManualGearCar implements Car {
  start(): void {
    this.engageClutch();
    this.startEngine();
    const dashboardInfo = this.readDashboard();
    // ... Check dashboard_info and raise if anything goes wrong ...
    console.log(`Dashboard: ${JSON.stringify(dashboardInfo)}`);
    if (!dashboardInfo.ok) {
      throw new Error("Something is not OK");
    }
    this.shiftGear(1);
    this.releaseClutch();
    console.log("Car started!");
  }

  readDashboard(): Record<string, any> & { ok: boolean } {
    return {
      foo: "bar",
      default: "values",
      ok: true,
    };
  }

  engageClutch(): void {
    console.log("[DefaultClutch] engaged!");
  }

  releaseClutch(): void {
    console.log("[DefaultClutch] released!");
  }

  abstract startEngine(): void;

  abstract shiftGear(level: number): void;
}


class Picasso extends ManualGearCar {
  readDashboard(): Record<string, any> & { ok: boolean; } {
    const info = super.readDashboard();
    return { ...info, brand: "Citroen" };
  }

  startEngine(): void {
    console.log("[Picasso] engine started!");
  }

  shiftGear(level: number): void {
    console.log(`[Picasso] gear shifted to: ${level}`);
  }
}

const createPicasso = (): Car => {
  return new Picasso();
}

const createTesla = (): Car => {
  return {
    start() {
      console.log("[Tesla] Wow it just starts!");
    }
  }
}

function main() {
  const picasso = createPicasso();
  picasso.start();

  const tesla = createTesla();
  tesla.start()
}

main();

你会用惯用的 TypeScript 做什么?

谢谢!

typescript oop idioms
1个回答
0
投票

看起来您正在描述模板方法模式

如果您喜欢更实用的风格,就像许多其他设计模式一样,这可以使用高阶函数轻松实现。然后,您可以将函数作为参数传递来代替抽象方法。

© www.soinside.com 2019 - 2024. All rights reserved.