使用打字稿模型类时将条件替换为多态

时间:2019-05-29 13:16:12

标签: angular typescript polymorphism

我已经建立了一个生活模拟游戏,现在我试图清除代码并使之更加面向对象。尽管进行了几天的搜索,但我还是很难用多态性替换条件语句。

所以我有一个component.ts游戏模型和一个cell模型。单元模型除其他外还包含属性status: boolean。可能是死的还是活的。然后,我为用户提供了在启动时切换单元格状态的功能。因此,我试图通过状态创建一个抽象类,然后创建两个死亡或存活的子类,但是我不确定这是否是正确的方法。

这是cell.model

import { Coordinates } from './coordinates.model';

export class Cell {
  private coordinates: Coordinates;
  public status: string;


  constructor(coordinates) {
    this.coordinates = coordinates;
    this.status = new Alive().status;
  }

  getCoordinates(): Coordinates {
    return this.coordinates;
  }

  toggleCell(): void {
    console.log(this.status)
  }

}

export abstract class Status {
  status: string;
  abstract setStatus(): string;
}

export class Alive extends Status {
  status = 'alive';
  setStatus(): string {
    return this.status = 'dead';
  }
}

export class Dead extends Status {
  status = 'dead';
  setStatus(): string {
    return this.status = 'alive';
  }
}

在下面可以看到的游戏模型中,我使用条件更改了状态

toggleCell(cellIndex: number) {
  const cell: Cell = this.cells[cellIndex];
  // if (this.cells[cellIndex].status === 'dead') {
  //     this.cells[cellIndex].status = 'alive';
  //     this.addToLivingCells(cellIndex);

  // } else {
  //     this.cells[cellIndex].status = 'dead';
  //     this.removeFromLivingCells(cellIndex);
  // }

  cell.toggleCell()
}

所以我要做的是删除条件语句,并使用多态性根据当前状态将死点的状态从死点切换为活着并返回。

让我知道是否需要其余代码。

预先感谢

2 个答案:

答案 0 :(得分:0)

对于这种简单的情况,我认为您的要求过于复杂。对于这种情况,此代码就足够了:

export class Cell {
    private coordinates: Coordinates;
    public status: 'alive' | 'dead';

    constructor(coordinates) {
        this.coordinates = coordinates;
        this.status = 'alive';
    }

    getCoordinates(): Coordinates {
        return this.coordinates;
    }

    toggleCell(): void {
        this.status = this.status === 'alive' ? 'dead' : 'alive';
        console.log(this.status);
    }
}

答案 1 :(得分:0)

这里的示例似乎太简单了,难以打扰多态性……只有在您发现自己做了很多switch (this.status)之类的事情时,这才是值得的。但是,我可能会这样做:

首先,除非您确实具有一些通用功能,否则我将使Status成为接口而不是抽象类:

interface Status {
  readonly status: "alive" | "dead";
  getOtherStatus(): Status;  // instead of setStatus()
  otherFunctionalityThatChangesDependingOnStatus(): void; // etc
}

然后,如果您确实有两个类AliveDead,则您绝对不想更改status中的setStatus()字符串,因为那样会完全破坏您的模型。因为AliveDead是两个不同的类,所以一个实例不能成为另一个实例(当然,它是technically can,但您不应尝试这样做)。而且,由于Alive实例必须始终是Alive实例,因此将this.status更改为"dead"几乎没有意义。在您的原始实现中,const a = new Alive()仍然有效,然后a.setStatus()使其成为“死亡Alive”,然后a.setStatus()将其保留为“死亡Alive” ,因为实施了Alive.setStatus()

相反,至少应将AliveDead实例的状态视为immutable。与其通过this.status使setStatus()突变,不如通过Status 返回与其他状态相对应的getOtherStatus()对象。如果AliveDead是不可变的,则没有真正的理由要携带每个类的多个实例(因为const a = new Alive()const b = new Alive()将使两个不同的对象准确地起作用在所有情况下都相同)。因此,您可以执行以下操作:

class Alive implements Status {
  static readonly instance = new Alive(); // the one instance of Alive
  private constructor() {}
  readonly status = "alive";
  getOtherStatus() {
    return Dead.instance;
  }
  otherFunctionalityThatChangesDependingOnStatus() {
    console.log("It's good to be alive!");       
  }
}

class Dead implements Status {
  static readonly instance = new Dead(); // the one instance of Dead
  private constuctor() {}
  readonly status = "dead";
  getOtherStatus() {
    return Alive.instance;
  }
  otherFunctionalityThatChangesDependingOnStatus() {
    console.log("I'm out of here!")
  }
}

因此,您永远不会呼叫new Alive()new Dead();相反,您可以抓住Alive.instanceDead.instance。最后,您可以使Cell依赖于Statusstatus的{​​{1}}属性应该是Cell实例,而不是字符串。这样便可以获取StatusAlive的面向对象的行为。您将Dead初始化为status,然后通过将Alive.instance设置为toggleCell()this.status

this.status.getOtherStatus()

让我们对其进行测试:

class Cell {
  private coordinates: Coordinates;
  public status: Status;

  constructor(coordinates: Coordinates) {
    this.coordinates = coordinates;
    this.status = Alive.instance;
  }

  getCoordinates(): Coordinates {
    return this.coordinates;
  }

  toggleCell(): void {
    this.status = this.status.getOtherStatus();
    console.log(this.status);
  }
}

看起来不错。好的,希望这会有所帮助。祝你好运!

Link to code