заменить условный на полиморфизм при использовании класса машинописной модели - PullRequest
0 голосов
/ 29 мая 2019

Я создал игру симулятор жизни, и теперь я пытаюсь очистить код и сделать его более объектно-ориентированным.Несмотря на несколько дней поиска, мне трудно заменить условные выражения полиморфизмом.

Итак, у меня есть 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()
}

, так что яхочу сделать, это удалить условные выражения и использовать полиморфизм, чтобы переключать статус с мертвого на живой и обратно в зависимости от текущего статуса.

Дайте мне знать, если остальная часть кода необходима.

Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 29 мая 2019

Пример, приведенный здесь, кажется слишком простым, чтобы беспокоиться о полиморфизме ... это, вероятно, будет того стоить, если вы обнаружите, что много делаете 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!

Выглядит хорошо,Хорошо, надеюсь, это поможет.Удачи!

Ссылка на код

0 голосов
/ 29 мая 2019

Я думаю, что ваша заявка слишком сложна для такого простого случая. Для этого случая этого кода достаточно:

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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...