OOPでの継承の概念を説明しようとする場合、一般的な例は哺乳類の例です。私見、これは本当に悪い例です。初心者がこの概念を間違った方法で使用するようになるためです。さらに、彼らが日常の設計作業で直面することは一般的な設計ではありません。
それでは、継承を使用して解決される素敵でシンプルで具体的な問題は何でしょうか?
哺乳類のような純粋に学術的な例には何も問題はありません。また、四角形/四角形の例も気に入っています。これは、実際の分類法が必ずしも期待する継承関係に直接変換されない理由を示しているためです。
私の意見では、最も標準的な毎日の例はGUIツールキットです。それは誰もが使用しているものですが、その初心者はそれらが内部でどのように機能するかについて推論していない可能性があります。特定の実装に関する詳細な知識がなくても、すべてのコンテナ、すべてのウィジェット、イベントなどに共通する動作について話すことができます。
私の実際の例は、単純なHRアプリケーションのドメインモデルです。 Employeeという基本クラスを作成できると言います。もちろん、マネージャーも従業員です。
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Code { get; set; }
public string GetInsuranceHistory()
{
// Retrieving insurance history based on employee code.
}
}
次に、開発者は従業員、テスターは従業員、プロジェクトマネージャーは従業員。したがって、それらはすべて、従業員クラスからinheritできます。
変化するものをカプセル化します... テンプレートメソッドパターン を示します。これは、基本クラスに共通の動作を置き、サブクラスに変化する動作をカプセル化することで、継承の有用性を示します。
UI controls
およびStreams
も、継承の有用性の非常に良い例です。
私は職場でカメラを使用しています。異なるモデルに接続するデバイスがあるため、抽象的な「カメラクラス」があり、すべてのモデルはこのクラスから継承して、そのカメラの特定の機能をサポートします。これは実際の例であり、理解するのは難しくありません。
これは私の脳から飛び出した別の例です:
class Element _ { double atomicWeight; //要素の原子量 double atomicNumber; //要素の原子番号 文字列プロパティ; //要素のプロパティ //その他、もしあれば } class Isotope extends Element_ //要素の同位体が存在する可能性がある { double halflife; //その他(ある場合) }
オブジェクトのすべてのインスタンスは、継承の有用性の具体例です。
具体的にはclass継承の場合、分類法の世界にいるので、それらを使用するシステムの目的によって大幅に異なります。動物/哺乳動物の例では、生物学からの一般的でうまくいけば親しみのある分類法を使用していますが、プログラミングの問題の大部分では(言及したように)ほとんど役に立ちません。
だから普遍的なものを試してください:プログラムの概念。すべてのプログラムが開始、実行、終了します。すべてのプログラムには、名前とオプションのコマンドラインパラメータがあります。したがって、基本的なProgramクラスは、実行を開始し、コマンドライン引数を取得して処理し、メインロジックを実行し、適切にシャットダウンするのに非常に役立ちます。
これが、非常に多くのオブジェクト指向プログラミング言語がProgramクラス、またはProgramクラスのように動作するものを提供する理由です。
実際の例では、何かがTypeA
とTypeB
の両方である可能性が常にある例を示しているため、ほとんどの場合間違っています。しかし、多くの言語の単一の継承階層では、それが許可されていません。
プログラムするほど、継承から離れます。
ここでは「継承」という言葉も不適切に使用されています。たとえば、父親の特性の約50%と母親の特性の50%を継承します。本当にあなたのDNAはあなたの父のDNAの半分とあなたの母親のDNAの半分の構成です。それは生物学が実際に 継承よりも構成を優先する であり、あなたもそうするべきだからです。
単にインターフェースを実装すること、またはさらに優れた「ダックタイピング」と依存関係の注入を実装することは、オブジェクト指向プログラミングに不慣れな人々に教えるにははるかに優れたものです。
良い例は、ソートの比較関数です。
template<class T>
class CompareInterface {
public:
virtual bool Compare(T t1, T t2) const=0;
};
class FloatCompare : public CompareInterface<float> { };
class CompareImplementation : public FloatCompare {
public:
bool Compare(float t1, float t2) const { return t1<t2; }
};
template<class T>
void Sort(T*array, int size, CompareInterface<T> &compare);
唯一の問題は、初心者がパフォーマンスよりも優れたコードよりも重要だと考えることが多すぎることです...
私は彼らに実際の例を示します。たとえば、ほとんどのUIフレームワークでは、何らかの「Dialog」、「Window」、または「Control」クラスから派生して独自のUIフレームワークを作成します。
この非哺乳類、非鳥、非魚の例は役立つかもしれません:
public abstract class Person {
/* this contains thing all persons have, like name, gender, home addr, etc. */
public Object getHomeAddr() { ... }
public Person getName() { ... }
}
public class Employee extends Person{
/* It adds things like date of contract, salary, position, etc */
public Object getAccount() { ... }
}
public abstract class Patient extends Person {
/* It adds things like medical history, etc */
}
その後
public static void main(String[] args) {
/* you can send Xmas cards to patients and employees home addresses */
List<Person> employeesAndPatients = Factory.getListOfEmployeesAndPatients();
for (Person p: employeesAndPatients){
sendXmasCard(p.getName(),p.getHomeAddr());
}
/* or you can proccess payment to employees */
List<Employee> employees = Factory.getListOfEmployees();
for (Employee e: employees){
proccessPayment(e.getName(),e.getAccount());
}
}
注:秘密は教えないでください:人は哺乳類を拡張します。
私の実世界の例は車両です:
public class Vehicle
{
public Vehicle(int doors, int wheels)
{
// I describe things that should be
// established and "unchangeable"
// when the class is first "made"
NumberOfDoors = doors;
NumberOfWheels = wheels;
}
public void RollWindowsUp()
{
WindowsUp = true;
}
// I cover modifiers on properties to show
// how to protect certain things from being
// overridden
public int NumberOfDoors { get; private set; }
public int NumberOfWheels { get; private set; }
public string Color { get; set; }
public bool WindowsUp { get; set; }
public int Speed { get; set; }
}
public class Car : Vehicle
{
public Car : base(4, 4)
{
}
}
public class SemiTruck : Vehicle
{
public SemiTruck : base(2, 18)
{
}
}
この例は、必要に応じて詳細に取得できます。また、車両にアタッチされているあらゆる種類のプロパティを使用して、教えたいモディファイアの使用法を説明できます。
代数的表現の階層についてはどうでしょう。継承と構成の両方が含まれているので良いです:
+--------------------+------------------------+
| Expression |<------------------+ |
+--------------------+----------+ | |
| + evaluate(): int |<---+ | | |
+--------------------+ | | | |
^ | | | |
| | | | |
+--------------+ +---------------+ +-------------+ ...
| Constant | | Negation | | Addition |
+--------------+ +---------------+ +-------------+
| -value: int | | | | |
+--------------+ +---------------+ +-------------+
| +evaluate() | | +evaluate() | | +evaluate() |
| +toString() | | +toString() | | +toString() |
+--------------+ +---------------+ +-------------+
Addition(Constant(5), Negation(Addition(Constant(3),Constant(2))))
(5 + -(3 + 2)) = 0
ルート式の定数を除いて、他のすべての式は両方とも式であり、1つ以上の式を含みます。