我已经建立了一个生活模拟游戏,现在我试图清除代码并使之更加面向对象。尽管进行了几天的搜索,但我还是很难用多态性替换条件语句。
所以我有一个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()
}
所以我要做的是删除条件语句,并使用多态性根据当前状态将死点的状态从死点切换为活着并返回。
让我知道是否需要其余代码。
预先感谢
答案 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
}
然后,如果您确实有两个类Alive
和Dead
,则您绝对不想更改status
中的setStatus()
字符串,因为那样会完全破坏您的模型。因为Alive
和Dead
是两个不同的类,所以一个实例不能成为另一个实例(当然,它是technically can,但您不应尝试这样做)。而且,由于Alive
实例必须始终是Alive
实例,因此将this.status
更改为"dead"
几乎没有意义。在您的原始实现中,const a = new Alive()
仍然有效,然后a.setStatus()
使其成为“死亡Alive
”,然后a.setStatus()
将其保留为“死亡Alive
” ,因为实施了Alive.setStatus()
。
相反,至少应将Alive
和Dead
实例的状态视为immutable。与其通过this.status
使setStatus()
突变,不如通过Status
返回与其他状态相对应的getOtherStatus()
对象。如果Alive
和Dead
是不可变的,则没有真正的理由要携带每个类的多个实例(因为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.instance
或Dead.instance
。最后,您可以使Cell
依赖于Status
。 status
的{{1}}属性应该是Cell
实例,而不是字符串。这样便可以获取Status
和Alive
的面向对象的行为。您将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);
}
}
看起来不错。好的,希望这会有所帮助。祝你好运!