Come migliorare un pattern 'enum class with methods'

1

Nel corso di molti anni, mi sono sempre ritrovato a riconsiderare questo progetto, quindi volevo ottenere un feedback sulla mia soluzione.

Problema:

Ho bisogno di una quantità limitata di oggetti = istanze da una classe e non voglio esporre l'opzione per crearne altri. Voglio anche un facile accesso a loro da qualsiasi luogo e operatori come uguali / non uguali.
Devono essere istanze di classe, in quanto devono avere metodi, quindi un enum non funziona.

(semplificato) Esempio:

Prendi in considerazione ad esempio un gioco simile ad un gioco di scacchi.

  1. Ci sono tre colori di tessere per il tabellone necessario, più chiaro e più scuro, e una tessera di dimensioni diverse dove vengono messi i pezzi presi. Inoltre,
  2. i pezzi hanno un colore, in genere bianco o nero; e io uso NoColor per i campi vuoti.

Entrambi gli esempi, ogni istanza dovrebbe sapere come disegnare e serializzare se stessa.

Opzione ovvia:

Se faccio un enum semplice, i valori non possono trasportare metodi, quindi finisco con i metodi Draw e Serialize in qualche altra classe, che sono fondamentalmente un brutto interruttore / caso.

La mia soluzione:

Mi piace

  1. proteggi il costruttore e,
  2. crea istanze statiche (pubbliche) all'interno della classe (ora C ++ 17 lo consente anche direttamente con inline ).

'Ogni istanza viene creata con un const' tipo ' in esso (fondamentalmente un enum ), impostato tramite il costruttore.
Ovunque mi occorrano le informazioni, utilizzo il puntatore const per l'istanza statica . Ciò consente di _compare e assegnarli facilmente e consente anche di chiamare le loro funzioni membro secondo necessità.
Permette anche agli altri giochi di derivare dalla classe e aggiungere nuove istanze statiche, ad esempio, un gioco a tre giocatori può aggiungere un'istanza Red all'interno di una classe derivata. Dato che distribuisco i puntatori alla classe base ovunque, è polimorfico e il codice non deve gestire in alcun modo il nuovo colore speciale ...

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'};
};

Esempio di utilizzo:

...
// 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; }
  ...
}

Domanda:

Vado avanti e indietro nella mia mente tra questo è un odore di codice o una soluzione piuttosto buona e pulita. Quindi è un odore di codice?
In quale altro modo sarebbe meglio progettarlo?

Ho letto molto su Singletons, e non penso che mi farebbero del bene (a parte il fatto che alcune persone pensano che siano anche un buon odore di codice).

    
posta Aganju 29.04.2018 - 05:34
fonte

0 risposte

Leggi altre domande sui tag