web-dev-qa-db-ja.com

抽象化と多態性の違いは何ですか

私は2つのOOP概念をよく理解していないようです。abstractionpolymorphismが何であるか、できれば実際の例とコードで説明できますか?

ありがとうございました。

30
Sambath Prum

抽象化

分数クラスを想像してください:

_class fraction:
    int denominator
    int numerator
_

その2つのオブジェクト:

_fraction(obj1): denominator=-1 numerator=-1
fraction(obj2): denominator=1  numerator=1
_

両方のオブジェクトの値は1:_(1/1) == (-1)/(-1)_です。あなたは彼らが外とは違ったふるまいをすることを期待しないでしょう。それは抽象化です。オブジェクトが保持しているデータを論理的なビューに抽象化します。裏でさえ、他にもあります。理論的には、等価グループが異なる等価関係が得られます。

_[1]=(1, 1), (-1, -1), (5, 5), ...
[2]=(2, 4), (-2, -4), ...
...
_

そして、内部の詳細を外部に抽象化する抽象化関数があります:

_f((1, 1)) = [1]
f((-1, -1)) = [1]
_

concrete値からオブジェクトのabstract値にマッピングします。これを行うには、たとえば(-1、-1)を(1、1)にマッピングするコンストラクターを記述し、クラスのequals関数を記述します。

ポリモーフィズム

ペンと2つの派生クラスを想像してください。

_class pen:
    void draw(int x, int y)

class pen_thin extends pen:
    void draw(int x, int y) { color(x, y) = green; }

class pen_thick extends pen:
    void draw(int x, int y) { color(x, y) = green; 
                              color(x, y+1) = green; }
and two objects:
    pen_thin(p1)
    pen_thick(p2)
_

両方のペンで描くことができます。一般的な「ペン」は自分自身を描くことはできません。これは、pen_thin、pen_thick、および他の多くのペンへの単なるインターフェースです。あなたは言う:obj1.draw(1、0); obj1が太いペンであるか細いペンであるかは、ユーザーとしての問題ではなく、コンパイル時のコンパイラーにとっても重要ではありません。呼び出しはポリモーフィックに動作します。それは動的ポリモーフィズム(実行時に発生します)であり、これが通常の意味です。 静的ポリモーフィズムはコンパイル時に発生します:

_class colorizer:
    void colorize(shirt s)
    void colorize(pants p)
_

それはオーバーロードと呼ばれています。 obj.colorize(something)を呼び出します。シャツを参照して呼び出すと、シャツを着たバージョンが呼び出されます。パンツの参照を付けて呼び出すと、パンツのバージョンが呼び出されます。ここで行われる選択はコンパイル時です。

これら2つは、オブジェクト指向パラダイムの最も重要な特性の1つです。

抽象化。

オブジェクト指向は、ソフトウェアを実世界のオブジェクトとしてモデル化します。ただし、顧客が持つ可能性のあるすべてのプロパティ、または従業員が持つすべてのプロパティをモデル化するのは非常に難しい(そして役に立たない)でしょう。

オブジェクトの興味深い属性のみをリストすることにより、OOは、特定のドメインでそのオブジェクトを効果的に使用できます。それは抽象化です。

たとえば、HRシステムの従業員は、オンライン書店とは非常に異なる属性を持つ場合があります。細かいところまで抽象化しており便利です。

ポリモーフィズム。

オブジェクトは、同じインターフェースを維持しながら、「タイプ」に応じて異なる動作をする場合があります。

これはどういう意味ですか?

たとえば、オンラインストアシステムには、従業員の2つのサブクラスがある場合があります。

A)内部の従業員。

B)請負業者

そして、内部購入の割引を計算する方法

内部従業員の割引は次のように計算されます:会社で働いた年ごとに10%+ 2%+それぞれのために2%.. mmhh子

業者の割引は10%

支払う金額を計算する次のコード:

 public Amount getAmountToPay( Product product, Employee internalCustomer ) { 
      Amount amount = product.getPrice();
      amount.applyDiscount( internalCustomer.getDiscount() );
      return amount;
 }

2つの異なる種類の従業員に対して異なる結果を生成します

class Employee { 
    public int getDiscount();
}


class InternalEmployee extends Employee { 
     public int getDiscount() { 
        return 10 + 2 * getWorkedYears() + 2 * getNumberOfChilds();
     }
 }

 class Contractor extends Employee { 
      public int getDiscount() { 
          return 10;
     }
 }

これは実際の多型です。のようなものを持っている代わりに

 Amount amount = product.getPrice();

 if( employee.isContractor() ) { 
      amount.applyDiscount( 10 );
 } else if( employee.isSomthingElse() ) {
      amount.applyDiscount( 10 * 2 * getYrs() + 2 * getChilds() );
 } else if ( employee.contidions, condigions, conditions ) {
      amount.applyDiscount( getSomeStrageRuleHere() );
 }

ランタイムに計算するものを選択させます。タイプに応じてプログラムの動作が異なるようです:

      Amount amount = product.getPrice();
      amount.applyDiscount( internalCustomer.getDiscount() );
      return amount;

ちなみに、この例では、 "Amount"は実際の概念を抽象化したものであり、doubleまたはIntegerとして表すこともできますが、独自のクラスに設定すると、内部にInterestingメソッドが含まれる場合があります。

これがお役に立てば幸いです。

13
OscarRyz

抽象化と多態性は、オブジェクト指向に限定されることなく、重要な概念です。混乱に加えて、「抽象化」という言葉は複数の方法で使用されます。以下は、簡単なチートシートと1つの例です。

  • データの抽象化情報の隠蔽を意味します。通常、隠されているのはデータ構造の表現です。例:セットを実装していますが、セットがリスト、平衡型二分木、または不平衡型二分木で表されているかどうかはわかりません。正しく完了しましたコードを壊すことなく表現を変更できます

  • ポリモーフィズム異なるタイプで再利用を意味します。したがって、私のセットの例では、すべて同じコードを使用して、社会保障番号のセット、フルネームのセット、またはフルーツバットのセットを作成できます。

もちろん、抽象的でポリモーフィックなクラスを定義できます。

ポリモーフィズムを実装するには2つの方法がありますであるため、ポリモーフィズムはさらに混乱します。 parametric polymorphismでは、セットをanyタイプの値、または何らかの制約を満たす任意のタイプの値で再利用できます。 最も明白な例C++テンプレートです。あなたが書くなら

class Set <T> { ... }

次に、Tは、セットに含まれるオブジェクトのタイプです(表記<T>は、いわゆる「タイプパラメータ」を示します。これにより、parametricpolymorphismになります)。

サブタイプポリモーフィズムでは、タイプが特定のタイプのサブタイプであるオブジェクトでのみ、セットを再利用できます。たとえば、以下のメソッドを提供するオブジェクトのセットのみを作成できる場合があります。 SmalltalkやRubyなどのいわゆるオブジェクト指向言語では、いわゆるダックタイピング(先のとがった頭の理論家は行動サブタイピングと呼ぶことがあります) /)、メソッドの存在は十分です。 JavaまたはC++のような言語で、継承でサブタイプを統合とすると、ポリモーフィズムの使用はサブクラスに制限されます)特定のクラスの

最後に、私のような古いオナラは手続き型の抽​​象化について話します。これは、頻繁に一緒に使用される一連のステートメントを取得して、それらを後で再利用できるプロシージャまたはメソッドに配置できることを意味します。それはおそらくあなたの質問に密接な関係はありません。

それで、あなたは混乱することについて気分が良くなりますか?

12
Norman Ramsey

抽象化とは、背景の詳細​​や説明を含めずに、本質的な機能を表現する行為を指します。クラスは抽象化の概念を使用し、抽象属性のリストとして定義されます。

ソフトウェア抽象化の一例は、JavaのObject.equals(Object o)メソッドです。このオブジェクトをパラメーターとして渡されたオブジェクトと比較することはわかっていますが、それがどのように実装されるかは正確にはわかりませんし、知る必要もありません(クラスの実装者でない限り)。

ポリモーフィズムとは、複数の形態を取る能力を意味します。メソッドは、インスタンスごとに異なる動作をする場合があります。動作は、操作で使用されるデータ型によって異なります。

ポリモーフィズムの古典的な例の1つは、Animalクラスをルートとする継承ツリーを使用しています。すべての動物にはmakeNoise()メソッドがありますが、DogクラスとCatクラスの実装は異なります。これにより、動物参照タイプを使用して犬と猫を参照できます。

_Animal a = new Dog();
Animal b = new Cat();
_

これで、いずれかのAnimalインスタンスでmakeNoise()を呼び出すことができ、適切なノイズが発生することがわかります。これは、動物のコレクションがあり、実行時に各タイプが実際にどのタイプなのか正確に分からない場合に特に便利です。

6
Bill the Lizard

どちらの用語もオブジェクト指向プログラミングで頻繁に使用されますが、それらは特にそのコンテキストに限定されません。

抽象化は何か他のものの一般化です。視点で一歩高い。たとえば、階層は企業の組織構造の抽象概念と見なすことができます。一般に、その下にあるもの(その基本型など)のコンテキストで使用されます。抽象化のポイントは、より一般的な性質の少ないコードを記述して、より多くの問題に対して実行できるようにすることです。たとえばスプレッドシートは、特定のタイプの情報ストレージを可能にする抽象概念です。 もっと?

ポリモーフィズムは一般化でもありますが、ランタイムコンテキストで発生します。互いに区別できない場所でオブジェクトにアクセスする方法がある場合、さまざまなオブジェクトタイプの束はポリモーフィックです。つまり、すべてのオブジェクトの外観は同じでも違っていても同じです。これの目的は、コードを大幅に減らすことです。 1つの一般化されたソリューションを記述して、異なるタイプごとに異なる順列をすべて書き込む必要をなくすことができます。グラフィックライブラリを作成する場合は、「形状」を処理する抽象的なコードを作成するだけで、円や四角などの異なるタイプごとにコードを作成する必要があります。

これらは両方とも、プログラマーがより少ないリソースでより多くのことを実行できるようにするコードのプロパティを中心とした用語です。コードが少ないほどバグが少なく、安定性が高く、保守が容易になります。代わりの方法は、「ブルートフォース」を使用して、非常に具体的な(そして非常に壊れやすい)コードの何百万および何百万行もの行を打ち消すことです。より多くのコードは修正が難しく、最新の状態を維持するのがはるかに困難です。

ポール。

4
Paul W Homer

短い答え:抽象化は概念であり、ポリモーフィズムは動作です

3
Steven A. Lowe

抽象化と多態性は性質が似ており、目的は異なります。

例のために。

運転免許証:運転を許可されている車両のクラスについて言及する免許が与えられます。ライセンスには、当局が許可する車両のクラスが記載されていますが、運転する特定の車またはブランドを定義または記載していません。これが抽象化です。

ここでライセンス抽象クラ​​スとそのメソッド、許可されている車両抽象メソッドです。

さて、ここで、ポリモーフィズムは、個々のライセンスが権限によってさまざまな人々に割り当てられるさまざまな方法です。さまざまな要件に応じて、いくつかは軽自動車用に発行され、一部は重車両用に発行されます。ここでは、ライセンスは基本クラスであり、他の種類のライセンスはその子クラスであり、is-a関係に従います。商用ライセンスはライセンスです。

したがって、抽象化はフォロワークラスに実装の独立性を与える一般的なガイドラインであり、ポリモーフィズムは親クラスによって設定されたメソッド/ルールをオーバーライドする差分アプローチです。

2
dhirwan

PS:最近学習を始めましたJava答えは私の観察に基づいています。間違っている場合は修正してください。

抽象化とポリモーフィズムは、基本的にプログラミングのほとんど同じことを行います。

たとえば、車を見てみましょう。

フォードミニバン、フェラーリエキゾチック、ランドローバーSUV、BMWセダンのいずれであるかは関係ありません。これらはすべて、車の基本設計、つまりエンジン、ステアリングホイール、ギアボックス、ライト、インジケーターに準拠しています。リストは続く。それらの違いは、フェラーリのような特定の実装がミニバンよりも強力なエンジンを持っているかもしれない、suvが別のギアボックスを持っているかもしれないということです、エキゾチック)これはpolymorphismです。基本的なアイデアは、他の仕様を追加することによって継承または実装されます。さまざまな形式(サブクラス)で実装されている4輪車(スーパークラス)

現在、Abstraction、定義により、詳細を非表示にし、ユーザーに何が必要かをユーザーに表示することを意味します。

もう一度車の例を見てみましょう。ギアを使用していますが、ギアがどのように機能し、速度が変化するかなどのメカニズムは正確にはわかりません。

パートのコーディングに移ります。

抽象クラスは不完全なクラスであり、その名のとおり、クラスが抽象的であるためには、スーパークラスを継承するサブクラスによって完了する必要がある不完全なメソッドが必要です。抽象メソッドを完了しない場合、それらも不完全なままになります。 。

abstract class car {
  abstract void gear();
}

class sedan extends car {
 public void gear()
 {
  //complete the method
 }
}

また、クラスが完全でないため、抽象クラスのオブジェクトを作成できません。しかし、これらの抽象クラスには静的メソッド、引数、具象メソッドを含めることができますが、抽象化するには、1つの抽象メソッドが必要です。したがって、1つの基本的な抽象スーパークラスが他のサブクラスで実装され、そこで完了します。メソッド宣言を調べることにより、メソッドが正確に何をしているか、何を返すかを推定できます。しかし、抽象メソッドがどのように実装されるのか正確にはわかりません。

抽象クラスまたはインターフェースを使用することにより、Javaで抽象化を実現できます。誰もが知っているように、抽象クラス、インターフェースには抽象メソッドが含まれています

それらがどのように機能するかを推定することしかできません。対応する抽象クラスまたはインターフェースを実装するクラスにメソッド実装を提供すると、それらがどのように機能するかを知ることができます。

HENCE、抽象は基本的にポリモーフィズムを助けます。

0
Alok

オブジェクト指向のコンテキストにおける抽象化の実際の意味に関する混乱は理解しやすいです。それは、継承の概念、カプセル化、さらにはポリモーフィズムの概念に少しでも追加するだけです。これらの3つの概念を習得すれば、自然に組み込まれると(特に継承)、「抽象化」にあまり関心を持つ必要はありません。

まず、「抽象化」という用語には複数の意味があり、たとえばカプセル化には抽象化が必要であることを示すことは不正確ではないことに注意してください。クラスの属性を保護するために修飾子にアクセスし、それらを処理するメソッド(つまり、カプセル化)を公開すると、クラスのユーザーは、自分でそれらを処理する方法を心配する必要がなくなります。したがって、ある意味では、クラスを設計するとき、メソッドと属性を適切にカプセル化することによってabstractを行います-クラスのユーザーが行う必要があることはすべてそれを使用することです適切なメソッドを呼び出すことにより、これは抽象化の一形態です。

さらに、直感的に考えると、ポリモーフィズムは抽象化の形式でもあります:コードはいくつかのクラスによって提供されるメソッドを呼び出しますが、それがどのように行われるかはわかりません実際のクラスタイプが決定されるまで(実行時に)動作します。したがって、ポリモーフィックな振る舞いは一種の抽象化であると述べるのは正しいことです。

ただし、OOPの特性を説明するためにスタンドアロンの用語として使用する場合、抽象化は、適切なクラス階層の形式で議論されているシステムの適切な表現として理解する必要があります。そのため、抽象化は、プログラムで使用される予定のクラスの適切な設計に至るデザイナーのメンタルプロセスの結果です。 (優れた!)投稿を引用するには javarevisitedブログにあります

...抽象化は設計レベルで詳細を隠し、カプセル化は実装レベルで詳細を隠します。

上記の説明は正しいですが、「詳細を非表示にする」の部分が誤っていると思います-次のように言い換えます

抽象化は設計の詳細に関係し、クラス階層がどのように見えるかを決定し、カプセル化は詳細な実装を隠します

著者と公平を期すために、このアイデアは彼の記事に美しく添えられています。この意味合いの「抽象化」という用語は Head First Object-Oriented Analysis and Design のような優れた本にも見られ、そこからのステートメントを引用します。

2つ以上の場所で共通の動作を見つけたら、その動作をクラスに抽象化し、その動作を共通のクラスで再利用してください。

ここで抽象化の使い方に注意してください:「その動作をクラスに抽象化するように見えます」。ここで、to abstractは、クラス階層を適切に設計することを意味します上記の抽象化は、継承とカプセル化の概念を利用して、クラスを便利に使用することにより、ドメインの表現として定義できます

Javaの特定のケースでは、抽象化は interfaces および abstract classes を使用して実装され、カプセル化は private、protectedおよびpackageアクセス修飾子 を使用して実装されます。

簡単に言うと、抽象化は概念的であり、ポリは行動的です。 OOPで抽象化を実現するには、Polyが必要です。

オブジェクト指向プログラミングの抽象化は、私が言う概念または設計パターンです。これにより、より良い分離、疎結合、つまりテスト容易性、再利用性と拡張性が可能になります。すべてを達成するには、ポリ、継承/拡張などが必要です。

0