Descubrí las interfaces y comencé a amarlas. La belleza de una interfaz es que es un contrato, y cualquier objeto que cumpla ese contrato se puede usar donde se requiera esa interfaz.
El problema con una interfaz es que no puede tener una implementación predeterminada, lo cual es un problema para las propiedades mundanas y derrota a DRY. Esto también es bueno, porque mantiene la implementación y el sistema desacoplado. La herencia, por un lado, mantiene un acoplamiento más apretado y tiene el potencial de romper la encapsulación.
Caso 1 (Herencia con miembros privados, buena encapsulación, estrechamente acoplada)
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 una interfaz)
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: (¿lo mejor de ambos mundos?)
Similar al caso 1 . Sin embargo, imagine que (hipotéticamente) C ++ no permitió métodos de anulación, excepto aquellos métodos que son puramente virtuales .
Entonces, en el Caso 1 , anular do_work () causaría un error en tiempo de compilación. Para solucionar esto, configuramos do_work () como virtual puro y agregamos un método separado increment_money_earned (). Como ejemplo:
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(); ); .
};
Pero incluso esto tiene problemas. ¿Qué pasa si dentro de 3 meses, Joe Coder crea un empleado médico, pero se olvida de llamar a increment_money_earned () en do_work ()?
La pregunta:
¿Es el caso 3 superior al caso 1 ? ¿Se debe a una "mejor encapsulación" o a un "acoplamiento más flexible", o alguna otra razón?
¿Es el caso 3 superior al caso 2 porque se ajusta a DRY?