Questo cattivo design è per un'interfaccia Shape?

1

Sto creando un programma di editing vettoriale in C ++ e ho bisogno di un'interfaccia Shape che altre classi concrete implementeranno. È richiesto che nessuna ereditarietà dell'implementazione sia consentita. Il documento di progettazione dice che se hai bisogno di polimorfismo, usa le interfacce . Se hai bisogno di riutilizzo del codice, utilizza la composizione .

L'interfaccia Forma è:

class Shape
{
  public:

   virtual void get_name()=0;
   virtual void set_name()=0;
   virtual void get_linewidth()=0;
   virtual void set_linewidth()=0;

   ...
   ...about 20 other getters/setters
   ...

   virtual void draw()=0;
   virtual int area()=0;
   virtual void rotate(int angle)=0;

}

La classe Circle:

class Circle: public Shape
{
  string name;
  int line_width;
  int angle_of_rotation;
  int radius;
public:
  string get_name(){ return name; }
  string set_name(string name){ this->name=name; }
  ...
  ...about 20 other getters/setters
  ...

  int area()
  {
    return PI*pow(this->radius,2);
  }

}

Non ho alcun problema con questo, eccetto che le proprietà comuni devono essere ripetute per ogni tipo di forma ! Questo è risolto usando l'ereditarietà, ma io non posso usarlo .

Quindi, creo una classe ShapeProperties

class ShapeProperties
{
  string name;
  int line_width;
  int angle_of_rotation;

public:

  string get_name(){ return name; }
  string set_name(string name){ this->name=name; }

  ...
  ...about 20 other getters/setters
  ...

}

e un metodo properties () per l'interfaccia:

virtual ShapeProperties* properties()=0;

Un utente farebbe quindi:

Shape *shape = new Circle();
shape->properties()->set_name("my shape");
shape->properties()->set_line_width(4);
int area = shape->area();

La mia domanda: questo buon design? Questo cattivo design? Ci sono problemi evidenti? Come potrebbe essere migliorato?

    
posta MustafaM 27.02.2012 - 09:17
fonte

2 risposte

2

È un cattivo progetto perché hai implementato una sottoclasse per qualcosa che non è una vera sottoclasse. Un cerchio è semplicemente un esempio di una FunctionalShape, al contrario di una VertexShape. Gli esempi di FunctionalShapes sono cerchi, ellissi e cose simili. La funzione utilizzata per generare la forma è solo dati, ed è una cattiva idea creare diverse sottoclassi per rappresentare cose diverse che sono solo dati.

Ciò che il tuo codice dimostra è che la restrizione a un'interfaccia è inutile, perché la tua logica può essere ridotta in modo semplice a non richiedere una spedizione dinamica. La maggior parte potrebbe essere anche una variabile membro pubblico. Tecnicamente, non hai utilizzato l'ereditarietà dell'implementazione, ma in realtà, hai, l'hai appena codificato in modo leggermente diverso.

La realtà è che senza utilizzare l'ereditarietà dell'implementazione, in C ++ non è possibile rendere questo codice utilizzabile. C'è una ragione per cui quella caratteristica del linguaggio esiste ed è perché non averla è stupida e inutile e rende la vita molto dura senza una valida ragione.

La composizione può riutilizzare la logica. Non può riutilizzare la classe descrizione , che è la parte che ripetete all'infinito (e inutilmente). Non esiste una soluzione entro i limiti specificati.

    
risposta data 27.02.2012 - 09:53
fonte
0

shape->properties()->set_name("my shape");

Questo è chiamato treno relitto, quindi è meglio evitare, perché il metodo che ha bisogno di chiamare properties() e poi set_name() ha bisogno di sapere troppo. A meno che shape non sia una struttura dati, e nel tuo caso non sembra esserci.

Se è necessario utilizzare il metodo per ottenere le proprietà, quindi renderle struttura dei dati (senza alcun metodo e con tutte le variabili dei membri pubblici) e restituire const riferimento:

const ShapeProperties& properties() const

quindi le proprietà assomigliano a:

struct ShapeProperties
{
  std::string name;
  int line_width;
  int angle_of_rotation;
  // ...
};
    
risposta data 27.02.2012 - 09:47
fonte