継承の有用性をどのように説明できますか?[閉まっている]


16

OOPの継承の概念を説明しようとする場合、一般的な例は哺乳類の例です。私見、これは本当に悪い例です。なぜなら、初心者がこの概念を間違った方法で使用するようになるからです。さらに、彼らが日々のデザインの仕事で直面するのは一般的なデザインではありません。

それでは、継承を使用して解決される素敵でシンプルで具体的な問題は何でしょうか?


1
「一般的な例はしばしば哺乳類です」?どういう意味ですか?これに関するリンク、参照、または引用を提供できますか?
S.Lott


3
継承=ビルゲイツの子供の信託基金の有用性を説明するための最良の実例は何でしょうか?
マーティンベケット

1
@クリス:この質問はどのように建設的ではないのですか?1人の質問者と14人の回答者が全員の時間を無駄にしていると宣言していますか?
ダンダスカレスク

@DanDascalescu-2年前に「閉鎖は建設的でないと考えてください:積み重ねられた答えから判断すると、これは典型的なリスト/投票の質問のように見えます」というフラグに応えて閉鎖されました。これが間違っていると思われる場合は、編集して、そうでないことを明確にし、コミュニティがレビューキューを再開して決定できるようにします。
ChrisF

回答:


15

哺乳類のような純粋に学術的な例には何の問題もありません。長方形/正方形の例も気に入っています。なぜなら、実際の分類法が必ずしも期待する継承関係に直接変換されない理由を指摘しているからです。

私の意見では、最も標準的な毎日の例はGUIツールキットです。それは誰もが使用しているものですが、その初心者は彼らが内部でどのように機能するかについて推論していないかもしれません。特定の実装に関する詳細な知識を必要とせずに、すべてのコンテナ、すべてのウィジェット、イベントなどに共通する動作について話すことができます。


5
GUIツールキットの+1 ...そして、シェイプの例も気に入っています。1つのシェイプが最小のdraw()をベースとし、子孫のシェイプがdraw()をカスタマイズしています。
ヤティサガデ11

14

私の実際の例は、単純な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.
    }
}

次に、開発者従業員テスター従業員プロジェクトマネージャー従業であることを説明します。したがって、それらはすべて従業員クラスから継承できます。


2
継承の利点を示すために、開発者が従業員とどのように異なるかを示すことも興味深いかもしれません。違いがなければ、Developerクラスを作成する必要はまったくありません。
デビッド

3
クラスのようにもEmployee思えますabstract
StuperUser

+1これは私の教師のほとんどが使用した例であり、私はそれが本当に好きでした。それは完全に理にかなっており、継承の使用方法に関する実世界の例を示しました。
デビッドピーターマン

18
ただし、a Developerとaの両方である必要がある人が常に少なくとも1人いるため、これは実際には機能しませんTester。別の同様の状況は、あなたがCustomerとを持っている連絡先データベースですが、Supplierそのようなシステムを作成した人なら誰でもあなたに言うように、a Companyは両方である場合が常にあります。それが、これらの例のほとんどが間違った方向にあなたを導く理由です。
スコットホイットロック

11

さまざまなものをカプセル化します... テンプレートメソッドパターンを示します。共通の動作を基本クラスに入れ、さまざまな動作をサブクラスにカプセル化することにより、継承の有用性を示します。

UI controlsそしてStreamsまた、継承の有用性のために非常に良い例です。


その工場が良い例だと思います。
Let_Me_Be

1
@Let_Me_Be:ファクトリと継承の関係は、その性質上間接的すぎると思います。確かに、具象型を生成し、抽象型/基本型を返しますが、インターフェイス型だけを返すこともできます!私見は、古典的な動物の例よりも良くありません。
ファルコン

@Let_Me_Be:また、抽象ファクトリーは、さまざまな継承階層(アイテム用、工場用)を含む非常に複雑な例です。私はそれが継承の良い使い方だと思いますが、良い簡単な例ではありません。
ファルコン

3

覚えている

オブジェクトのすべてのインスタンスは、継承の有用性の具体例です!

明確にクラス継承を意味する場合、現在はタクソノミーの世界にいます。それらは、それらを使用するシステムの目標によって大きく異なります。動物/哺乳類の例では、生物学から得られた一般的な分類法を使用しますが、プログラミングの問題の大部分では(おっしゃるように)ほとんど役に立ちません。

それで、普遍的な何かを試してください:プログラムの概念。すべてのプログラムが開始、実行、および終了します。すべてのプログラムには、名前とオプションのコマンドラインパラメーターがあります。したがって、実行を開始し、コマンドライン引数を取得して処理し、メインロジックを実行し、正常にシャットダウンするには、基本プログラムクラスが非常に役立ちます。

これが、非常に多くのオブジェクト指向プログラミング言語がプログラムクラス、またはプログラムクラスとまったく同じように動作するものを提供する理由です。


それで、あなたはそれの中に多くのプログラムを持っているプログラムをプログラムしますか?:)私の経験では、Programmオブジェクトはほとんど常に継承のないシングルトンであるため、私見は最良の例ではありません。
ケプラ

@keppla:Javaまたは.NETを使用したことがありますか?.NETには明示的なProgramクラスがあり、Javaには暗黙的です。彼らはシングルトンではない
スティーブンA.ロウ

バージョン1.4.2前後でJavaを使用しました。当時、静的なボイドメインしかなかったので、少し変更されたと思います。Programmクラスのインスタンスを複数持つ典型的な理由は何でしょうか?
ケプラ

@keppla:javaのstatic void mainは、エントリクラスにプログラムを暗黙的に表させます。プログラムを実行するすべてのユーザーは、その新しいインスタンスを作成します。現在、Google Chromeのインスタンスが3つ、Word文書が4つ、メモ帳が3つ、Windows Explorerが2つあります。それらがすべてシングルトンである場合、私はそれを行うことができません。
スティーブンA.ロウ

1
少し定義を広げると思います。class Programm { public static void main(String[] args) { system.out.println('hello world'); }}は最小限のJavaプログラムです。私がそれを呼ぶとき、プログラムのインスタンスはありません。プログラムは何からも継承しません。(crhomeで行うように)3つのプロセスを開始すると、3つのプログラムが存在する場合がありますが、メモリの個々の領域にはまだ1つのプログラムしかありません。私見、シングルトンは、マシンごとではなく、「プロセスごとに1つのインスタンスのみ」を意味します。その場合、シングルトンを作成することは不可能であり、コードを2回実行することを妨げるものはありません。
ケプラ

3

私は職場でカメラを使用しています。異なるモデルに接続するデバイスがあるため、抽象的な「カメラクラス」があり、すべてのモデルがこのクラスを継承して、そのカメラの特定の機能をサポートします。これは現実の例であり、理解するのは難しくありません。


2
これは、たとえばa Cameraとa の両方のモデルがある場合に壊れる可能性がありますPhone(私たちは皆、今ポケットに入れています)。どの基本クラスから継承する必要がありますか?または、ICameraとの両方を実装するだけではいけませんIPhoneか?(ハハ)
スコットホイットロック

2
@Scott:IPhoneインターフェースを実装することはできません。そうしないと、Appleから訴えられます。
メイソンウィーラー

3

化学要素の例

これは私の脳から飛び出した別の例です:

クラスElement_
{
    double atomicWeight; //要素の原子量
    double atomicNumber; //要素の原子番号
    文字列プロパティ。//要素のプロパティ
    //その他、もしあれば
}


class Isotope extends Element_ //要素の同位体が存在する可能性があります
{
    二重半減期;
   //その他がある場合

}

2
(?必要があります)atomicNumberは、おそらく...の整数を指定できますが
アンドリュー

そのために継承を使用しません。isotopeの特殊なケースではありませんElemenet。むしろにElementプロパティがありますIsotope
CodesInChaos

2

彼らは両方とも何かの可能性は常にあります例与えるので、実世界の例はほとんど常に間違ってそれを取得TypeAし、TypeB多くの言語の単一継承階層がそれを許可していませんが。

プログラムを作成すればするほど、継承から離れることができます。

ここでは「継承」という言葉も不適切に使用されています。たとえば、父親の特性の約50%と母親の特性の50%を継承します。本当にあなたのDNAはあなたの父親のDNAの半分と母親のDNAの半分の組成です。それは、生物学は実際には継承よりも合成を好むからです。あなたもそうすべきです。

単純にインターフェースを実装するか、さらに良いことに「アヒル型付け」に加えて依存性注入を行うことは、オブジェクト指向プログラミングに慣れていない人々に教えるのにはるかに良いことです。


1

私は彼らに実際の例を見せたいだけです。たとえば、ほとんどのUIフレームワークでは、ある種の「ダイアログ」または「ウィンドウ」または「コントロール」クラスから派生して、独自のクラスを作成します。


1

良い例は、ソートの比較機能です。

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);

唯一の問題は、初心者があまりにも頻繁にパフォーマンスが良いコードよりも重要だと思うことです...


0

私の実世界の例は乗り物です:

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)
    {

    }
}

この例では、好きなだけ詳細に表示できます。また、車両に添付されているあらゆる種類のプロパティを使用して、教えたいモディファイアの使用を説明できます。


2
コードを改善するために継承をどのように使用できるかを理解するのに新しいプログラマーが近づくことはないので、私は例として車両を使用することを常に嫌っていました。乗り物は非常に複雑な機械であり、プログラマーではない人の心の中にある、抽象的なものではない多くのアイデアを思い起こさせます。これをコードで記述しようとすると、平均的な初心者は、例から多くの詳細が残されていると信じさせ、何かを動かすことに近づいていないという感覚を与えます。誰かがそれを私に説明するために乗り物を使用しようとしたとき、まさにそう感じたので、私は経験からこれを言います。
リウォーク

@ Stargazer712:車両は、主に好きなだけ複雑にしたり単純にしたりできるため、使用しています。彼の生徒のレベルを決定するのはインストラクターの判断に任せます。私は、一般的な基本を説明する車両の単純なプロパティを使用して、基本的なOOPを妻(プログラミング経験がゼロ)に説明しました。すべての車両にドアがあり、すべての車両に車輪があります。オブジェクトの例は、授業計画が悪いことのせいにすることはできません。
ジョエルイーサートン

あなたの妻はコードを書こうとしていませんでした。私がすることができ非常に安全に車両の例では、私は、継承を理解するために何もしなかったと言います。継承の記述に使用するものは何でも、完全実用的でなければなりません。目標は、非プログラマが理解できるような方法で説明することではありません。目標は、初心者のプログラマが使用できるような方法で説明することであり、それを行う唯一の方法は、プロのプログラマがどのように使用するかの初心者の例を示すことです。
リウォーク

@ Stargazer712:貧弱な授業計画の継承を最初に理解することができないと思います。また、私は乗り物を使って、私が働く後輩に相続を説明しました。そして、私は出くわす概念に問題を持ったことがありません。私の意見では、授業計画が綿密で適切に構築されていれば、車両オブジェクトは完全かつ実用的です。私がOOPを教えた30人ほどのインターンとジュニア開発者に直面しても、インターネット上の1人のランダムな人がそれを変えることはありません。乗り物が気に入らない場合は、投票して先に進みます。
ジョエルイーサートン

あなたが望むように
....-riwalk

0

この非哺乳動物、非鳥、非魚の例が役立つかもしれません:

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());
    }       

}

注:秘密を教えないでください:人は哺乳類を拡張します。


1
従業員の1人が患者になるまで機能します。
スコットホイットロック

この場合、PatientとEmployeeを抽象クラスではなくインターフェイスとして宣言する方が理にかなっていると思います。これにより、Personに複数のインターフェースを実装させる柔軟性が得られます。
ジンキム・

@JinKim-私は完全に同意します、それはより良いアプローチです。
スコットホイットロック

@JinKimこれらは排他的ではありません。特定の時点で従業員または患者として人を扱いますが、同時には扱いません。2つのインターフェイスは問題ありませんが、両方を実装する具体的なクラスEmployeePatientを何と呼ぶのでしょうか?いくつの組み合わせがありますか?
Tulainsコルドバ

具象クラスを好きなように呼び出すことができます。コードが従業員のみを扱うことを想定している場合、参照を従業員として宣言します。(つまり、従業員employee = new Person();)コードが患者のみを扱うことを想定している場合、参照を患者として宣言します。参照を具象クラスとして直接宣言することはほとんどありません。
ジンキム・

0

代数式の階層はどうですか。継承と構成の両方が含まれているので良いです:

+--------------------+------------------------+
| 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つ以上の式を含みます。


-1

例として鳥を使用します

チキン、アヒル、ワシのような

両方に爪、ペック、翼があることを説明しますが、属性は異なります。

鶏は飛べない、泳げない、虫を食べる、穀物を食べることができる

アヒルは飛べない、泳ぐことができる、穀物を食べることができる、虫を食べることができない

イーグルは飛べる、泳げない、虫を食べる、穀物を食べることができない


4
私はかつてその構図を読んで、インタフェースはおそらく飛ぶIEコンセプトのこのタイプを伝えるための最善の方法です、水泳など
dreza

アヒルは飛べない?!
アダムキャメロン14

-3

典型的なrails-cloneは多くの実用的な例を提供します:すべてのデータ操作をカプセル化する(抽象)基本モデルクラスがあり、すべてのHTTP通信をカプセル化する基本コントローラークラスがあります。


この答えがなぜ悪いのかを詳しく述べるように注意してください。
ケプラ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.