Пример, приведенный здесь, кажется слишком простым, чтобы беспокоиться о полиморфизме ... это, вероятно, будет того стоить, если вы обнаружите, что много делаете switch (this.status)
или тому подобное.Но вот как я могу это сделать:
Во-первых, я бы сделал Status
интерфейсом вместо абстрактного класса, если у вас нет общих функций:
interface Status {
readonly status: "alive" | "dead";
getOtherStatus(): Status; // instead of setStatus()
otherFunctionalityThatChangesDependingOnStatus(): void; // etc
}
Затем,если у вас есть два класса Alive
и Dead
, вы абсолютно не хотите изменять строку status
внутри setStatus()
, поскольку это полностью разрушает вашу модель.Поскольку Alive
и Dead
- это два разных класса, экземпляр одного не может стать экземпляром другого (ну, технически может , но вы не должны пытатьсясделай это).А поскольку экземпляр Alive
всегда должен быть экземпляром Alive
, нет смысла менять this.status
на "dead"
.В вашей первоначальной реализации const a = new Alive()
является живым, затем a.setStatus()
делает его "мертвым Alive
", а затем a.setStatus()
будет сохранять его "мертвым Alive
" из-за реализации Alive.setStatus()
.
Вместо этого вы должны рассматривать Alive
и Dead
как неизменные , по крайней мере, в отношении их статуса.Вместо того, чтобы изменять 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
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);
}
}
И давайте проверим:
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!
Выглядит хорошо,Хорошо, надеюсь, это поможет.Удачи!
Ссылка на код