OOPは初めてです。ポリモーフィズムが何であるかは理解していますが、実際に使用することはできません。別の名前の関数を持つことができます。アプリケーションにポリモーフィズムを実装する必要があるのはなぜですか。
古典的な答え:基本クラスShape
を想像してください。 GetArea
メソッドを公開します。 Square
クラスとRectangle
クラス、およびCircle
クラスを想像してみてください。個別のGetSquareArea
、GetRectangleArea
、およびGetCircleArea
メソッドを作成する代わりに、各派生クラスに1つのメソッドのみを実装できます。使用するShape
の正確なサブクラスを知る必要はありません。GetArea
を呼び出すだけで、具体的なタイプに関係なく結果が得られます。
このコードを見てください:
#include <iostream>
using namespace std;
class Shape
{
public:
virtual float GetArea() = 0;
};
class Rectangle : public Shape
{
public:
Rectangle(float a) { this->a = a; }
float GetArea() { return a * a; }
private:
float a;
};
class Circle : public Shape
{
public:
Circle(float r) { this->r = r; }
float GetArea() { return 3.14f * r * r; }
private:
float r;
};
int main()
{
Shape *a = new Circle(1.0f);
Shape *b = new Rectangle(1.0f);
cout << a->GetArea() << endl;
cout << b->GetArea() << endl;
}
ここで注意すべき重要なことは、使用しているクラスの正確なタイプを知る必要はなく、基本タイプだけを知っている必要があります。そうすれば、正しい結果が得られます。これは、より複雑なシステムでも非常に役立ちます。
楽しく学んでください!
_+
_を使用して2つの整数を追加し、次に_+
_を使用して整数を浮動小数点数に追加したことがありますか?
何かをデバッグするためにx.toString()
をログに記録したことがありますか?
名前を知らなくても、おそらくすでに多態性を高く評価していると思います。
厳密に型指定された言語では、さまざまな型のオブジェクトのリスト/コレクション/配列を持つために、ポリモーフィズムが重要です。これは、リスト/配列自体が正しい型のオブジェクトのみを含むように型付けされているためです。
たとえば、次のように想像してください。
_// the following is pseudocode M'kay:
class Apple;
class banana;
class kitchenKnife;
Apple foo;
banana bar;
kitchenKnife bat;
Apple *shoppingList = [foo, bar, bat]; // this is illegal because bar and bat is
// not of type Apple.
_
これを解決するには:
_class groceries;
class Apple inherits groceries;
class banana inherits groceries;
class kitchenKnife inherits groceries;
Apple foo;
banana bar;
kitchenKnife bat;
groceries *shoppingList = [foo, bar, bat]; // this is OK
_
また、アイテムのリストの処理がより簡単になります。たとえば、すべての食料品がメソッドprice()
を実装しているとすると、これは簡単に処理できます。
_int total = 0;
foreach (item in shoppingList) {
total += item.price();
}
_
これら2つの機能は、ポリモーフィズムが行うことの中核です。
ポリモーフィズムは、オブジェクト指向プログラミングの基礎です。つまり、1つのオブジェクトを別のプロジェクトとして持つことができます。したがって、オブジェクトがどのようにして他のものになることができますか?
これの主な利点の1つは、スイッチの実装です。データベースと通信する必要があるアプリケーションをコーディングしているとしましょう。そして、あなたはたまたまこのデータベース操作を行うクラスを定義し、追加、削除、変更などの特定の操作を行うことが期待されています。データベースは多くの方法で実装できることを知っています。それは、ファイルシステムやMySQLなどのRDBMサーバーと通信している可能性があります。そのため、プログラマとして、次のようなインターフェイスを定義します。
public interface DBOperation {
public void addEmployee(Employee newEmployee);
public void modifyEmployee(int id, Employee newInfo);
public void deleteEmployee(int id);
}
今、あなたは複数の実装を持っているかもしれません、私たちはRDBMS用のものと直接ファイルシステム用のものを持っているとしましょう
public class DBOperation_RDBMS implements DBOperation
// implements DBOperation above stating that you intend to implement all
// methods in DBOperation
public void addEmployee(Employee newEmployee) {
// here I would get JDBC (Java's Interface to RDBMS) handle
// add an entry into database table.
}
public void modifyEmployee(int id, Employee newInfo) {
// here I use JDBC handle to modify employee, and id to index to employee
}
public void deleteEmployee(int id) {
// here I would use JDBC handle to delete an entry
}
}
ファイルシステムデータベースを実装しましょう
public class DBOperation_FileSystem implements DBOperation
public void addEmployee(Employee newEmployee) {
// here I would Create a file and add a Employee record in to it
}
public void modifyEmployee(int id, Employee newInfo) {
// here I would open file, search for record and change values
}
public void deleteEmployee(int id) {
// here I search entry by id, and delete the record
}
}
Mainが2つの間を切り替える方法を見てみましょう
public class Main {
public static void main(String[] args) throws Exception {
Employee emp = new Employee();
... set employee information
DBOperation dboper = null;
// declare your db operation object, not there is no instance
// associated with it
if(args[0].equals("use_rdbms")) {
dboper = new DBOperation_RDBMS();
// here conditionally, i.e when first argument to program is
// use_rdbms, we instantiate RDBM implementation and associate
// with variable dboper, which delcared as DBOperation.
// this is where runtime binding of polymorphism kicks in
// JVM is allowing this assignment because DBOperation_RDBMS
// has a "is a" relationship with DBOperation.
} else if(args[0].equals("use_fs")) {
dboper = new DBOperation_FileSystem();
// similarly here conditionally we assign a different instance.
} else {
throw new RuntimeException("Dont know which implemnation to use");
}
dboper.addEmployee(emp);
// now dboper is refering to one of the implementation
// based on the if conditions above
// by this point JVM knows dboper variable is associated with
// 'a' implemenation, and it will call appropriate method
}
}
ポリモーフィズムの概念は多くの場所で使用できます。1つのプラチクルの例は次のとおりです。画像デコレーターを作成していて、jpg、tif、pngなどの画像の束全体をサポートする必要があるため、アプリケーションはインターフェースを定義して動作しますその上に直接。そして、jpg、tif、pgnなどのそれぞれのさまざまな実装の実行時バインディングがいくつかあります。
他の重要な用途の1つは、Javaを使用している場合、ほとんどの場合はListインターフェースで作業するため、アプリケーションの成長やニーズの変化に応じて、ArrayListや他のインターフェースを使用できます。
ポリモーフィズムの利点は、クライアントコードがメソッドの実際の実装を気にする必要がないことです。次の例を見てください。ここでは、CarBuilderはProduceCar()について何も認識していません。車のリスト(CarsToProduceList)が渡されると、それに応じて必要なすべての車が生成されます。
class CarBase
{
public virtual void ProduceCar()
{
Console.WriteLine("don't know how to produce");
}
}
class CarToyota : CarBase
{
public override void ProduceCar()
{
Console.WriteLine("Producing Toyota Car ");
}
}
class CarBmw : CarBase
{
public override void ProduceCar()
{
Console.WriteLine("Producing Bmw Car");
}
}
class CarUnknown : CarBase { }
class CarBuilder
{
public List<CarBase> CarsToProduceList { get; set; }
public void ProduceCars()
{
if (null != CarsToProduceList)
{
foreach (CarBase car in CarsToProduceList)
{
car.ProduceCar();// doesn't know how to produce
}
}
}
}
class Program
{
static void Main(string[] args)
{
CarBuilder carbuilder = new CarBuilder();
carbuilder.CarsToProduceList = new List<CarBase>() { new CarBmw(), new CarToyota(), new CarUnknown() };
carbuilder.ProduceCars();
}
}
ポリモーフィック演算から得られる最も重要な利点の1つは、拡張機能です。同じ操作を使用でき、既存のインターフェースや実装を変更することはできません。これは、新しいものの必要性に直面したためです。
ポリモーフィズムに必要なのは、設計の決定を簡素化し、設計をより拡張可能でエレガントにすることです。また、開閉原理( http://en.wikipedia.org/wiki/Open/closed_principle )とSOLID( http://en.wikipedia.org/wiki/Solid_%28Object_Oriented_Design%29 )これは、キーを理解するのに役立ちますOO原則。
追伸「動的ポリモーフィズム」( http://en.wikipedia.org/wiki/Dynamic_polymorphism )について話していると思います。 「静的なポリモーフィズム」( http://en.wikipedia.org/wiki/Template_metaprogramming#Static_polymorphism )。
ポリモーフィズムを使用すると、オブジェクトを使用するコードを記述できます。その後、既存のコードが変更なしで使用できる新しいクラスを後で作成できます。
たとえば、ライブラリから食料品店に車両を誘導する関数Lib2Groc(vehicle)
があるとします。車両に左折するように指示する必要があるため、特に車両オブジェクトでTurnLeft()
を呼び出すことができます。その後、誰かがホバークラフトのような新しい車両を発明した場合、それはLib2Groc
変更なし。
ポリモーフィズムは必要ありません。
あなたがするまで。
その後、friggenは素晴らしい。
多くの場合に対処する簡単な答え:
誰かが物事のコレクションを通過する必要があります。タイプMySpecializedCollectionOfAwesomeのコレクションを要求するとします。しかし、あなたはAwesomeのインスタンスをリストとして扱ってきました。したがって、今度は、MSCOAのインスタンスを作成し、List <T>にあるAwesomeのすべてのインスタンスをそのインスタンスに入力する必要があります。お尻の大きな痛みですね
まあ、彼らがIEnumerable <Awesome>を要求した場合、Awesomeの多くのコレクションの1つをそれらに渡すことができます。配列(Awesome [])、リスト(List <Awesome>)、またはAwesomeの監視可能なコレクション、またはIEnumerable <T>を実装するAwesomeを保持するその他のオブジェクトをそれらに渡すことができます。
ポリモーフィズムの力により、タイプセーフでありながら、このタイプまたはそのタイプを特別に処理する大量のコードを作成しなくても、インスタンスをさまざまな方法で使用できるほど十分に柔軟にすることができます。
オブジェクトが動的に呼び出されることもあると思います。オブジェクトがクラシックシェイプポリゴンの三角形、正方形などであるかどうかは不明です。例。
したがって、そのようなことをすべて残すために、派生クラスの関数を呼び出し、動的クラスの1つが呼び出されると想定します。
正方形、三角形、長方形のいずれでもかまいません。あなただけのエリアを気にします。したがって、渡された動的オブジェクトに応じてgetAreaメソッドが呼び出されます。
タブ付きアプリケーション
私にとって良いアプリケーションは、タブ付きアプリケーション内の一般的なボタン(for all tabs)です-私たちが使用しているブラウザーでさえ、ポリモーフィズムを実装していますコンパイル時に使用しているタブがわからない(つまり、コード内)。常に実行時に決定されます(今すぐ!ブラウザを使用しているとき)