web-dev-qa-db-ja.com

パターン「メソッドを持つ列挙型クラス」を改善する方法

長年にわたり、私はいつもこのデザインを再考しているので、自分のソリューションに対するフィードバックを得たいと思っていました。

問題:

クラスから限られた量のobjects = instancesが必要であり、さらに作成するオプションを公開したくありません。また、どこからでも簡単にアクセスできるようにしたいと思います。
メソッドを持つ必要があるため、それらはクラスインスタンスである必要があります。そのため、enumは機能しません。

((簡略化)例:

たとえば、チェスのようなゲームを考えてみましょう。

  1. 必要なボードには、3つのタイルの色、ライターとダーカー、および異なるサイズのタイルがあり、そこに駒が置かれます。また、
  2. ピースには色があり、通常は白または黒です。空のフィールドにはNoColorを使用します。

どちらの例でも、各インスタンスはそれ自体を描画してシリアル化する方法を知っている必要があります。

明白なオプション:

単純な列挙型を作成すると、値にメソッドを含めることができないため、他のクラスのDrawメソッドとSerializeメソッドができてしまいます。これらは基本的に醜いスイッチ/ケースです。

私の解決策:

したい

  1. コンストラクタを保護し、
  2. クラス内に(パブリック)静的インスタンスを作成します(C++ 17では、inlineを使用して直接インスタンスを作成できるようになりました)。

'各インスタンスはconst' type 'を使用して作成され(基本的にはenum)、コンストラクターによって設定されます。
情報が必要なときはいつでも、const pointerをそのstatic instanceに使用します。これにより、簡単に_ compareassignを使用でき、必要に応じてメンバー関数を呼び出すこともできます。
これにより、他のゲームがクラスから派生して新しい静的インスタンスを追加することもできます。たとえば、3人のプレーヤーのチェスは、派生クラス内にRedインスタンスを追加できます。私はどこでも基本クラスへのポインターを渡すため、それは多態的であり、コードは新しい色の特別な色を処理する必要がありません...

class Color
{
protected:
  Color(char c) : color{c} {}
public:
  void Serialize(Archive& ar) const { ar << color; }

private:
  const char color;

public:  // the only instances ever to exists; handed around by pointer
  inline const static Color NoColor{'X'};   // C++17 syntax, otherwise
  inline const static Color White{'W'};     // separate line in .cpp needed
  inline const static Color Black{'B'};
};

class Chess3Color : public Color
{
protected:
  Chess3Color(char c) : Color{c} {}

public:
  inline const static Chess3Color Red{'R'};
};

使用例:

...
// create a White King
Piece* p = new WhiteKing{&Type::King, &Color::White, IDB_W_K_BMP};
...
if (p->IsColor(&Color::White)) { ... }
...
p->Serialize(ar);
...
class Piece
{
  ...
  // Piece member function for serialization
  void Serialize(Archive& ar)
  {
    type->Serialize(ar);
    color->Serialize(ar);
  }
  ...
  // check if this piece is of a certain color
  // note that pointer compare is good enough!
  bool IsColor(const Color* c) { return color == c; }
  ...
}

質問:

私は、これがコードの匂いか、それともかなり良いクリーンな解決策であるかを心の中で行き来しています。それはコードの匂いですか?
これは他にどのように設計する方が良いでしょうか?

私はシングルトンについてたくさん読んだのですが、シングルトンが私に役立ってくれるとは思えません(コードの匂いだと思っている人もいます)。

4
Aganju

限られた量のオブジェクト=クラスのインスタンスが必要であり、さらに作成するオプションを公開したくありません。どこからでも簡単にアクセスできるようにしたい

これは、チェスのゲームを設計および実装する方法のアプリオリの概念(2プレイヤーチェスゲームでも3プレイヤーチェスゲームでも)に動機づけられていると思われる不要な制約です。

チェスのゲームの主なオブジェクト(ゲームの目的ではない)は何ですか?

  1. ゲーム-メインオブジェクト。ゲーム内のすべてがこのオブジェクトから生じます。
  2. 2人(または3人)のプレーヤー。
  3. ボード。
  4. チェスの駒。

すべてのオブジェクトには状態があります。すべてのオブジェクトには、それに関連付けられた動作があります。さらに、ゲームのルールは、それらが互いにどのように相互作用することができるか、オブジェクトの状態がどのように変化するかを決定します。

言うことによって得られるものは何もありません:

  1. 2人(または3人)を超えるプレーヤーを作成することはできません。それはゲームオブジェクト次第です。ゲームが2人または10人のプレーヤーを作成することを選択した場合、プレーヤーの状態やその動作には影響しません。

  2. 複数のボードを作成することはできません。繰り返しますが、作成するボードの数をゲームオブジェクトに決定させます。

  3. 32個を超える作品を作成することはできません。もう一度、それはゲームオブジェクト次第です。ボードのサイズや駒の数を変えることで、チェスのメインゲームのバリエーションを簡単に作成できます。

チェスのバリエーションが面白いです。 https://en.wikipedia.org/wiki/List_of_chess_variants を参照してください。クラスを希望どおりに制約する理由はありません。

どちらの例でも、各インスタンスはそれ自体を描画してシリアル化する方法を知っている必要があります。

それは良いデザインではありません、私見。

ボードとピースは、さまざまな方法で描くことができます。ネットで見つけられる king of images を見てください。ボードとピースは、さまざまな方法で描くことができます。

ゲームとその構成オブジェクトは、さまざまな方法でシリアル化することもできます。

これらの操作の両方に 戦略パターン を使用することをお勧めします。

1
R Sahu