【问题标题】:replace conditional to polymorphism when using typescript model class使用打字稿模型类时将条件替换为多态
【发布时间】:2019-05-29 13:16:11
【问题描述】:

我已经构建了一个模拟生活的游戏,现在我正在尝试清理代码并使其更加面向对象。尽管搜索了几天,但我很难用多态性替换条件。

所以我有一个 component.ts 一个游戏模型和一个单元模型。单元模型包含属性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()
}

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

如果需要其余代码,请告诉我。

提前致谢

【问题讨论】:

  • 还没有真正看到在 Angular/TypeScript 中使用该模式。为什么你认为它比使用条件更好?
  • @SiddAjmera,我认为这是为了提高可扩展性/可重用性和测试,但不确定具体的好处。但是我的 Typescript 是 OOP,所以不应该也可以在这里应用吗?这就是为什么我想我无法在网上找到一个答案。大多数示例向您展示了如何创建类,但它们并未展示您如何从代码中实际调用它。在这种情况下,切换功能

标签: angular typescript polymorphism


【解决方案1】:

我认为你的方法对于这样一个简单的案例来说太复杂了。对于这种情况,这段代码就足够了:

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

【讨论】:

    【解决方案2】:

    这里的例子似乎太简单了,不用多态性来打扰......如果你发现自己做了很多switch (this.status) 或类似的事情,那可能才值得。但我可以这样做:

    首先,我会将Status 设为接口而不是抽象类,除非您实际上有一些通用功能:

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

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

    相反,您应该将AliveDead 实例视为immutable,至少就它们的状态而言。而不是通过setStatus() 改变this.status,您应该返回一个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 依赖于StatusCellstatus 属性应该是 Status 实例,而不是字符串。这就是您如何获得AliveDead 的面向对象行为。您将status 初始化为Alive.instance,然后将toggleCell() 设置为this.statusthis.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);
      }
    }
    

    让我们测试一下:

    const c = new Cell(null!);
    c.status.otherFunctionalityThatChangesDependingOnStatus(); // It's good to be alive!
    c.toggleCell();
    c.status.otherFunctionalityThatChangesDependingOnStatus(); // I'm out of here!
    c.toggleCell();
    c.status.otherFunctionalityThatChangesDependingOnStatus(); // It's good to be alive!
    

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

    Link to code

    【讨论】:

      猜你喜欢
      • 2019-05-03
      • 1970-01-01
      • 2022-01-22
      • 2019-09-26
      • 2020-06-25
      • 2021-09-18
      • 1970-01-01
      • 2023-01-20
      • 2022-07-07
      相关资源
      最近更新 更多