私はインターフェースを「発見」し、それらを愛するようになりました。インターフェイスの優れた点は、それがコントラクトであることであり、そのコントラクトを満たすオブジェクトは、そのインターフェイスが必要な場所であればどこでも使用できます。
インターフェースの問題は、それがデフォルトの実装を持つことができないことです。これは、ありふれたプロパティの苦痛であり、DRYを無効にします。これは、実装とシステムの分離を維持するため、これも良い方法です。一方、継承はより緊密な結合を維持し、カプセル化を壊す可能性があります。
ケース1(プライベートメンバーによる継承、適切なカプセル化、密結合)
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();
)
ケース2(単なるインターフェース)
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.
ケース3:(両方の長所?)
ケース1に似ています。ただし、(仮説的に)C ++では、純粋なvirtualであるメソッドを除いて、メソッドのオーバーライドが許可されていないと想像してください。
したがって、ケース1では、do_work()をオーバーライドすると、コンパイル時エラーが発生します。これを修正するには、do_work()を純粋仮想として設定し、別のメソッドincrement_money_earned()を追加します。例として:
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(); ); .
};
しかし、これにも問題があります。Joe Coderが今から3か月後にDoctor Employeeを作成したが、do_work()でincrement_money_earned()を呼び出すのを忘れた場合はどうなるでしょうか。
質問:
あるケース3は、より優れたケース1?それは「カプセル化の向上」または「疎結合性が高い」ためか、その他の理由によるのですか?
あるケース3よりも優れたケース2は、それはDRYに準拠しているため?