Ho "scoperto" le interfacce e ho iniziato ad amarle. La bellezza di un'interfaccia è che si tratta di un contratto e qualsiasi oggetto che adempie a quel contratto può essere utilizzato ovunque sia richiesta tale interfaccia.
Il problema con un'interfaccia è che non può avere un'implementazione predefinita, il che è una seccatura per proprietà banali e sconfigge DRY. Anche questo è positivo, perché mantiene disaccoppiate l'implementazione e il sistema. L'ereditarietà, invece, mantiene un accoppiamento più stretto e ha il potenziale di rompere l'incapsulamento.
Caso 1 (Eredità con membri privati, buona incapsulamento, strettamente accoppiata)
class Employee
{
int money_earned;
string name;
public:
void do_work(){money_earned++;};
string get_name(return name;);
};
class Nurse : public Employee:
{
public:
void do_work(/*do work. Oops, can't update money_earned. Unaware I have to call superclass' do_work()*/);
};
void HireNurse(Nurse *n)
{
nurse->do_work();
)
Caso 2 (solo un'interfaccia)
class IEmployee
{
virtual void do_work()=0;
virtual string get_name()=0;
};
//class Nurse implements IEmployee.
//But now, for each employee, must repeat the get_name() implementation,
//and add a name member string, which breaks DRY.
Caso 3: (il migliore dei due mondi?)
Simile al caso 1 . Tuttavia, immagina che (ipoteticamente) il C ++ non consentisse metodi di esclusione ad eccezione di quei metodi che sono puramente virtuali .
Quindi, nel caso 1 , l'override di do_work () causerebbe un errore di compilazione. Per risolvere questo problema, impostiamo do_work () come puro virtuale e aggiungiamo un metodo separato increment_money_earned (). Come esempio:
class Employee
{
int money_earned;
string name;
public:
virtual void do_work()=0;
void increment_money_earned(money_earned++;);
string get_name(return name;);
};
class Nurse : public Employee:
{
public:
void do_work(/*do work*/ increment_money_earned(); ); .
};
Ma anche questo ha problemi. E se tra 3 mesi, Joe Coder crea un impiegato medico, ma si dimentica di chiamare increment_money_earned () in do_work ()?
La domanda:
Il caso 3 è superiore al caso 1 ? È perché "incapsulamento migliore" o "accoppiamento più libero", o qualche altra ragione?
Il caso 3 è superiore al caso 2 perché è conforme al DRY?