JavaScriptでデザインパターン

クレーの大冒険をJavaScriptに移植するにあたってデザインパターンについて少し勉強してみた。

ChatGPTにゲームで使用するデザインパターンをJavaScriptで教えてとお願いしたら、

  • Singleton Pattern(シングルトンパターン)
  • Factory Pattern(ファクトリーパターン)
  • Observer Pattern(オブザーバーパターン)

の3パターンを勧められた。

Singleton Pattern(シングルトンパターン)

シングルトンパターンは、アプリケーション中で唯一のインスタンスを持つオブジェクトを作成するためのパターンです。これは、一部のゲームオブジェクトがアプリケーション中で一度しか存在しない場合に便利です。JavaScriptでは、シングルトンを作成するには、クラスのコンストラクタをプライベートにし、静的なメソッドで唯一のインスタンスを作成することができます。

class GameManager {
  constructor() {
    if (GameManager.instance) {
      return GameManager.instance;
    }
    GameManager.instance = this;
    this.score = 0;
    this.level = 1;
  }

  updateScore(points) {
    this.score += points;
  }

  updateLevel() {
    this.level++;
  }

  // 他のゲームマネージャーのメソッド...
}

const gameManager = new GameManager();
export default gameManager;

これって、グローバルで一つ生成して、それを色んなところで使い回せばいいんじゃないの?とおもったけど

また、クラスのインスタンスをグローバル変数などで参照することもできますが、これは推奨されません。代わりに、Singleton パターンを使用して、インスタンスが必要な場所でインスタンスを生成するようにすることが望ましいです。

らしい。なんでか深掘りしてみると。

Factory Pattern(ファクトリーパターン)

ファクトリーパターンは、複雑なオブジェクトを生成するためのパターンです。これは、アプリケーション中で異なる種類のオブジェクトを生成する必要がある場合に便利です。JavaScriptでは、ファクトリーパターンを実装するには、ファクトリー関数を使用することができます。

function createEnemy(type, x, y) {
  let enemy;

  if (type === "basic") {
    enemy = new BasicEnemy(x, y);
  } else if (type === "fast") {
    enemy = new FastEnemy(x, y);
  } else if (type === "big") {
    enemy = new BigEnemy(x, y);
  }

  return enemy;
}

const enemy1 = createEnemy("basic", 100, 50);
const enemy2 = createEnemy("fast", 200, 75);

Observer Pattern(オブザーバーパターン)

オブザーバーパターンは、オブジェクトの状態変化を監視し、関連するオブジェクトに通知するためのパターンです。これは、複数のオブジェクトが連携して動作するゲームで有用です。JavaScriptでは、オブザーバーパターンを実装するには、オブザーバーとして登録された関数を呼び出す Subject クラスを作成することができます。

class Subject {
  constructor() {
    this.observers = [];
    this.state = 0;
  }

  addObserver(observer) {
    this.observers.push(observer);
  }

  removeObserver(observer) {
    const index = this.observers.indexOf(observer);
    if (index > -1) {
      this.observers.splice(index, 1);
    }
  }

  notify() {
    this.observers.forEach((observer) => {
      observer.update(this.state);
    });
  }

  setState(state) {
    this.state = state;
    this.notify();
  }
}

class Observer {
  update(state) {
    console.log(`New state received: ${state}`);
  }
}

const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();
subject.addObserver(observer1);
subject.addObserver(observer2);

subject.setState(1); // New state received: 1
subject.setState(2); // New state received: 2

subject.removeObserver(observer1);

subject.setState(3); // New state received: 3

コメントする