私は 2 つの OOP の概念をよく理解していないようです。できれば実際の例とコードを使用して、抽象化とポリモーフィズムとは何かを説明していただけますか?
ありがとうございました。
私は 2 つの OOP の概念をよく理解していないようです。できれば実際の例とコードを使用して、抽象化とポリモーフィズムとは何かを説明していただけますか?
ありがとうございました。
分数クラスを想像してください:
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]
オブジェクトの具体的な値から抽象的な値にマップします。たとえば、(-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)
。シャツ参照で呼び出すと、シャツを取ったバージョンが呼び出されます。そしてパンツ参照で呼ぶとパンツバージョンと呼ばれます。ここでの選択はコンパイル時に行われます。
抽象化とポリモーフィズムは重要な概念であり、OO に限定されるものではありません。さらに混乱を招くのは、「抽象化」という言葉が複数の方法で使用されていることです。一例を含む簡単なチートシートを次に示します。
データの抽象化とは、情報の隠蔽を意味します。通常、隠されているのはデータ構造の表現です。例: 私はセットを実装していますが、セットがリスト、バランスのとれた二分木、またはアンバランスな二分木として表されているかどうかはわかりません。うまくやれば、コードを壊さずに表現を変更できます。
ポリモーフィズムとは、異なる型での再利用を意味します。したがって、私のセットの例では、社会保障番号のセット、フルネームのセット、またはフルーツバットのセットをすべて同じコードを使用して作成できます。
明らかに、抽象的でポリモーフィックなクラスを定義できます。
ポリモーフィズムを実装するには 2 つの方法があるため、ポリモーフィズムはさらに混乱を招きます。パラメトリック ポリモーフィズムでは、任意の型の値、または何らかの制約を満たす任意の型の値でセットを再利用できます。最も明白な例はC++ テンプレートです。あなたが書くなら
class Set <T> { ... }
次にT
、セットに含まれるオブジェクトの型です (表記<T>
は、いわゆる「型パラメーター」を示します。これにより、パラメトリックポリモーフィズムが実現されます)。
サブタイプ ポリモーフィズムでは、タイプが特定のタイプのサブタイプであるオブジェクトでのみセットを再利用できます。たとえば、以下のメソッドを提供するオブジェクトのセットのみを作成できる場合があります。Smalltalk や Ruby のような真のオブジェクト指向言語では、いわゆるダック タイピング(先のとがった理論家はそれを行動サブタイピングと呼ぶことがあります) を提供しますが、メソッドが存在するだけで十分です。Java や C++ など、サブタイプと継承を混同する言語では、ポリモーフィズムの使用が特定のクラスのサブクラスに制限される場合があります。(Java は、クラスのサブタイプとインターフェイスの別のサブタイプを使用することで、この問題をさらに混乱させます。)
最後に、私のような古いオナラは、手続き型の抽象化について話します。これは、頻繁に一緒に使用される一連のステートメントを取り、それらを再利用できるプロシージャまたはメソッドに組み込むことができることを意味します。それはおそらくあなたの質問とは関係ありません。
それで、あなたは混乱することについて気分が良くなりましたか?
これら 2 つは、オブジェクト指向パラダイムの最も重要な特徴の 1 つです。
オブジェクト指向は、ソフトウェアを実世界のオブジェクトとしてモデル化します。ただし、Customer が持つ可能性のあるすべてのプロパティ、または Employee が持つすべてのプロパティをモデル化するのは非常に困難です (そして役に立ちません)。
オブジェクトの興味深い属性のみをリストすることにより、OO は特定のドメインに対してそのオブジェクトを効果的に使用できます。それが抽象化です。
たとえば、人事システムの従業員は、オンライン書店とは非常に異なる属性を持つ場合があります。詳細を抽象化して、役に立つようにします。
オブジェクトは、同じインターフェイスを維持しながら、「タイプ」に応じて異なる動作をする場合があります。
これはどういう意味ですか?
たとえば、オンライン ストア システムには Employee の 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 つの異なる種類の Employee に対して異なる結果を生成します。
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 として表すこともできますが、独自のクラスに設定した方がよい興味深いメソッドが内部にある可能性があります。
これが役立つことを願っています。
抽象化とは、背景の詳細や説明を含めずに、本質的な機能を表現する行為を指します。クラスは抽象化の概念を使用し、抽象属性のリストとして定義されます。
ソフトウェアの抽象化の一例は、Java のObject.equals(Object o)
メソッドです。このオブジェクトをパラメーターとして渡されたオブジェクトと比較することはわかっていますが、正確にどのように実装されるかはわかりません (クラスの実装者でない限り)。
ポリモーフィズムとは、複数の形態を取る能力を意味します。メソッドは、インスタンスごとに異なる動作をする場合があります。動作は、操作で使用されるデータ型によって異なります。
ポリモーフィズムの古典的な例の 1 つは、Animal クラスをルートとする継承ツリーを使用します。すべての Animal にはmakeNoise()
メソッドがありますが、Dog クラスと Cat クラスではメソッドの実装が異なります。これにより、Animal 参照型を使用して任意の Dog および Cat を参照できます。
Animal a = new Dog();
Animal b = new Cat();
これで、いずれかの Animal インスタンスを呼び出すことができmakeNoise()
、それが適切な音を出すことがわかります。これは、動物のコレクションがあり、それぞれが実際にどのタイプであるかが実行時に正確にわからない場合に特に便利です。
簡単な答え: 抽象化は概念的であり、ポリモーフィズムは行動的です
どちらの用語もオブジェクト指向プログラミングで頻繁に使用されますが、特にそのコンテキストに限定されるわけではありません。
抽象化は何か他のものを一般化したものです。一歩上の視点。たとえば、ヒエラルキーは、会社の組織構造の抽象化と見なすことができます。一般に、下にあるもの (基本型など) のコンテキストで使用されます。抽象化のポイントは、本質的により一般的なコードを少なく記述して、より大きな一連の問題に対して実行できるようにすることです。たとえば、スプレッドシートは、特定のタイプの情報ストレージを可能にする抽象化です。もっと?
ポリモーフィズムも一般化ですが、実行時のコンテキストで発生します。互いに区別がつかない場合にアクセスする方法があれば、さまざまなオブジェクト型の束が多態的です。つまり、すべてのオブジェクトのルック アンド フィールは、たとえそうでなくても同じです。これの目的は、コードを大幅に削減することです。1 つの一般化されたソリューションを記述して、異なるタイプごとに異なる順列をすべて記述する必要がないようにすることができます。グラフィックス ライブラリを作成する場合は、「形状」を処理するための抽象的なコードを作成してから、円、正方形などのさまざまなタイプごとにコードを作成する必要があります。
これらは両方とも、プログラマーがより少ないリソースでより多くのことを行えるようにするコード内のプロパティを中心とした用語です。コードが少ないほどバグが少なく、安定性が高く、保守が容易です。別の方法は、「ブルート フォース」を使用して、何百万行もの非常に具体的な (そして非常に壊れやすい) コードを叩き出すことです。コードが増えると修正が難しくなり、最新の状態に保つのがはるかに難しくなります。
ポール。
抽象化とポリモーフィズムは本質的に似ていますが、目的が異なります。
たとえば。
運転免許証: 運転できる車両の種類が記載された免許証が発行されます。ライセンスには、当局によって許可されている車両のクラスが記載されていますが、どの特定の車やブランドを運転する必要があるかについては定義も言及もされていません。これが抽象化です。
ここでLicenseはAbstract クラスとそのメソッドであり、許可される車両はそのAbstract メソッドです。
ここで、ポリモーフィズムとは、個々のライセンスが当局によってさまざまな人々に割り当てられるさまざまな方法です。異なる要件に従って、軽自動車用に発行されるものもあれば、大型車用に発行されるものもあれば、商用車用に発行されるものもあります。ここで、License は基本クラスであり、他の種類のライセンスはその子クラスであり、is-a 関係にも従います。商用ライセンスはライセンスです。
したがって、抽象化はフォロワークラスに実装の独立性を与える一般的なガイドラインであり、ポリモーフィズムは親クラスによって設定されたメソッド/ルールをオーバーライドする差分アプローチです。
PS: 最近 Java の学習を始めた答えは、私の観察に基づいています。間違っている場合は修正してください。
抽象化とポリモーフィズムは、基本的にプログラミングでほぼ同じ作業を行います。
車を例にとってみましょう..
フォードのミニバン、フェラーリのエキゾチック、ランドローバーの SUV、BMW のセダンのいずれであっても、エンジン、ステアリング ホイール、ギア ボックス、ライト、インジケーターなど、自動車の基本設計に従っています。リストは続きます。それらが異なるのは、フェラーリがミニバンよりも強力なエンジンを持っている可能性があり、suv が異なるギアボックスを持っている可能性があるため、車 (ここではスーパークラス) がサブクラス (セダン、suv 、ミニバン) によって実装されているなど、特定の実装です。 、エキゾチック) これはポリモーフィズムであり、他の仕様を追加することによって継承または実装される基本的なアイデアです。4 輪車 (スーパークラス) がさまざまな形 (サブクラス) で実装されている
さて、抽象化は、定義上、詳細を隠し、ユーザーに必要なものを見せることを意味します..
もう一度車の例を見てみましょう.ギアを使用しますが、ギアがどのように機能し、速度とすべてを変更するかのメカニズムを正確には知りません..
パートのコーディングに移りましょう。
抽象クラスは不完全なクラスであり、名前が示すようにクラスを抽象化するには、スーパークラスを継承するサブクラスによって完了する必要がある不完全なメソッドが必要です。抽象メソッドを完了しない場合、それらも不完全なままになります.
abstract class car {
abstract void gear();
}
class sedan extends car {
public void gear()
{
//complete the method
}
}
また、クラスは完全ではないため、抽象クラスのオブジェクトを作成することはできません。ただし、これらの抽象クラスには静的メソッド、引数、具象メソッドを含めることができますが、それらを抽象化するには、1 つの抽象メソッドが必要です。したがって、1 つの基本的な抽象スーパークラスが他のサブクラスに実装され、そこで完成されます。メソッド宣言を見ると、メソッドが何をしているか、何を返すかを正確に推定できます。しかし、抽象メソッドがどのように正確に実装されるかはわかりません。
抽象クラスまたはインターフェースを使用することにより、Java で抽象化を実現できます。抽象クラスは誰もが知っているように、インターフェースには抽象メソッドが含まれています
それらがどのように機能するかを推定することしかできません。対応する抽象クラスまたはインターフェースを実装するクラスにメソッド実装を提供すると、それらがどのように機能するかがわかります。
したがって、抽象は基本的にポリモーフィズムに役立ちます。
非常に簡単。
抽象化は抽象化です。クラス 'Student' は、実際の学生を抽象化したものです。
ポリモーフィズムとは、ユーザーが気付かないように、あるクラスが別のクラスを表すことです。これは、クラスが同じインターフェイスを実装する場合、またはあるクラスが別のクラスから派生する場合に発生する可能性があります。クラス「HighSchoolStudent」は、クラス「Student」から派生しています。クラス 'Teacher' がオブジェクトに対して #attendance メソッドを呼び出すと、このオブジェクトが 'Student' クラスであるか 'HighSchoolStudent' クラスであるかがわからない場合があります。