OOPの継承の概念を説明しようとする場合、一般的な例は哺乳類の例です。私見、これは本当に悪い例です。なぜなら、初心者がこの概念を間違った方法で使用するようになるからです。さらに、彼らが日々のデザインの仕事で直面するのは一般的なデザインではありません。
それでは、継承を使用して解決される素敵でシンプルで具体的な問題は何でしょうか?
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.
}
}
次に、開発者は従業員、テスターは従業員、プロジェクトマネージャーは従業員であることを説明します。したがって、それらはすべて従業員クラスから継承できます。
Employee
思えますabstract
。
Developer
とaの両方である必要がある人が常に少なくとも1人いるため、これは実際には機能しませんTester
。別の同様の状況は、あなたがCustomer
とを持っている連絡先データベースですが、Supplier
そのようなシステムを作成した人なら誰でもあなたに言うように、a Company
は両方である場合が常にあります。それが、これらの例のほとんどが間違った方向にあなたを導く理由です。
さまざまなものをカプセル化します... テンプレートメソッドパターンを示します。共通の動作を基本クラスに入れ、さまざまな動作をサブクラスにカプセル化することにより、継承の有用性を示します。
UI controls
そしてStreams
また、継承の有用性のために非常に良い例です。
オブジェクトのすべてのインスタンスは、継承の有用性の具体例です!
明確にクラス継承を意味する場合、現在はタクソノミーの世界にいます。それらは、それらを使用するシステムの目標によって大きく異なります。動物/哺乳類の例では、生物学から得られた一般的な分類法を使用しますが、プログラミングの問題の大部分では(おっしゃるように)ほとんど役に立ちません。
それで、普遍的な何かを試してください:プログラムの概念。すべてのプログラムが開始、実行、および終了します。すべてのプログラムには、名前とオプションのコマンドラインパラメーターがあります。したがって、実行を開始し、コマンドライン引数を取得して処理し、メインロジックを実行し、正常にシャットダウンするには、基本プログラムクラスが非常に役立ちます。
これが、非常に多くのオブジェクト指向プログラミング言語がプログラムクラス、またはプログラムクラスとまったく同じように動作するものを提供する理由です。
class Programm { public static void main(String[] args) { system.out.println('hello world'); }}
は最小限のJavaプログラムです。私がそれを呼ぶとき、プログラムのインスタンスはありません。プログラムは何からも継承しません。(crhomeで行うように)3つのプロセスを開始すると、3つのプログラムが存在する場合がありますが、メモリの個々の領域にはまだ1つのプログラムしかありません。私見、シングルトンは、マシンごとではなく、「プロセスごとに1つのインスタンスのみ」を意味します。その場合、シングルトンを作成することは不可能であり、コードを2回実行することを妨げるものはありません。
私は職場でカメラを使用しています。異なるモデルに接続するデバイスがあるため、抽象的な「カメラクラス」があり、すべてのモデルがこのクラスを継承して、そのカメラの特定の機能をサポートします。これは現実の例であり、理解するのは難しくありません。
Camera
とa の両方のモデルがある場合に壊れる可能性がありますPhone
(私たちは皆、今ポケットに入れています)。どの基本クラスから継承する必要がありますか?または、ICamera
との両方を実装するだけではいけませんIPhone
か?(ハハ)
これは私の脳から飛び出した別の例です:
クラスElement_ { double atomicWeight; //要素の原子量 double atomicNumber; //要素の原子番号 文字列プロパティ。//要素のプロパティ //その他、もしあれば } class Isotope extends Element_ //要素の同位体が存在する可能性があります { 二重半減期; //その他がある場合 }
isotope
の特殊なケースではありませんElemenet
。むしろにElement
プロパティがありますIsotope
。
彼らは両方とも何かの可能性は常にあります例与えるので、実世界の例はほとんど常に間違ってそれを取得TypeA
し、TypeB
多くの言語の単一継承階層がそれを許可していませんが。
プログラムを作成すればするほど、継承から離れることができます。
ここでは「継承」という言葉も不適切に使用されています。たとえば、父親の特性の約50%と母親の特性の50%を継承します。本当にあなたのDNAはあなたの父親のDNAの半分と母親のDNAの半分の組成です。それは、生物学は実際には継承よりも合成を好むからです。あなたもそうすべきです。
単純にインターフェースを実装するか、さらに良いことに「アヒル型付け」に加えて依存性注入を行うことは、オブジェクト指向プログラミングに慣れていない人々に教えるのにはるかに良いことです。
私は彼らに実際の例を見せたいだけです。たとえば、ほとんどのUIフレームワークでは、ある種の「ダイアログ」または「ウィンドウ」または「コントロール」クラスから派生して、独自のクラスを作成します。
良い例は、ソートの比較機能です。
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);
唯一の問題は、初心者があまりにも頻繁にパフォーマンスが良いコードよりも重要だと思うことです...
私の実世界の例は乗り物です:
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)
{
}
}
この例では、好きなだけ詳細に表示できます。また、車両に添付されているあらゆる種類のプロパティを使用して、教えたいモディファイアの使用を説明できます。
この非哺乳動物、非鳥、非魚の例が役立つかもしれません:
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());
}
}
注:秘密を教えないでください:人は哺乳類を拡張します。
代数式の階層はどうですか。継承と構成の両方が含まれているので良いです:
+--------------------+------------------------+
| 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つ以上の式を含みます。
例として鳥を使用します
チキン、アヒル、ワシのような
両方に爪、ペック、翼があることを説明しますが、属性は異なります。
鶏は飛べない、泳げない、虫を食べる、穀物を食べることができる
アヒルは飛べない、泳ぐことができる、穀物を食べることができる、虫を食べることができない
イーグルは飛べる、泳げない、虫を食べる、穀物を食べることができない