私はpolymorphismでインターネット上で見つけたいくつかの可能な記事を読みました。しかし、その意味とその重要性を十分に理解できなかったと思います。ほとんどの記事では、なぜそれが重要であり、OOP(もちろんJavaScriptで)で多態的な振る舞いを実現することができるかについては述べていません。
コード例を実装する方法がわからないため、コード例を提供できません。そのため、私の質問は以下のとおりです。
私はこの例を持っています。しかし、このコードの結果がどうなるかは容易に理解できます。ポリモーフィズム自体についての明確なアイデアはありません。
function Person(age, weight) {
this.age = age;
this.weight = weight;
this.getInfo = function() {
return "I am " + this.age + " years old " +
"and weighs " + this.weight +" kilo.";
}
}
function Employee(age, weight, salary) {
this.salary = salary;
this.age = age;
this.weight = weight;
this.getInfo = function() {
return "I am " + this.age + " years old " +
"and weighs " + this.weight +" kilo " +
"and earns " + this.salary + " dollar.";
}
}
Employee.prototype = new Person();
Employee.prototype.constructor = Employee;
// The argument, 'obj', can be of any kind
// which method, getInfo(), to be executed depend on the object
// that 'obj' refer to.
function showInfo(obj) {
document.write(obj.getInfo() + "<br>");
}
var person = new Person(50,90);
var employee = new Employee(43,80,50000);
showInfo(person);
showInfo(employee);
多態性は、オブジェクト指向プログラミング(OOP)の教義の1つです。ビヘイビアを共有し、特定のビヘイビアで共有ビヘイビアをオーバーライドできるようにするオブジェクトを設計する習慣です。多態性は、これを実現するために継承を利用します。
OOPでは、すべてがオブジェクトとしてモデル化されていると見なされます。この抽象化は、自動車用のナットやボルトに至るまで、または年、メーカー、モデルを備えた単純な自動車タイプと同じくらい広い範囲にまで及ぶことができます。
ポリモーフィックな車のシナリオを作成するには、基本の車タイプがあり、車から継承する基本クラスの動作に加えて、車から継承する独自の動作を提供するサブクラスがあります。たとえば、サブクラスはTowTruckであり、年式とモデルがまだありますが、リフトの詳細と同じくらい複雑なIsTowingのフラグのような基本的な追加の動作とプロパティもあります。
人々と従業員の例に戻ると、すべての従業員は人間ですが、すべての人々は従業員ではありません。つまり、人々はスーパークラスになり、従業員はサブクラスになります。年齢や体重はあるかもしれませんが、給与はありません。従業員は人であるため、本質的に年齢と体重がありますが、従業員であるため、給与もあります。
そのため、これを容易にするために、最初にスーパークラス(Person)を書きます。
function Person(age,weight){
this.age = age;
this.weight = weight;
}
そして、Personに情報を共有する機能を提供します
Person.prototype.getInfo = function(){
return "I am " + this.age + " years old " +
"and weighs " + this.weight +" kilo.";
};
次に、Person、Employeeのサブクラスが必要です
function Employee(age,weight,salary){
this.age = age;
this.weight = weight;
this.salary = salary;
}
Employee.prototype = new Person();
そして、従業員により適合するものを定義することにより、getInfoの動作をオーバーライドします。
Employee.prototype.getInfo = function(){
return "I am " + this.age + " years old " +
"and weighs " + this.weight +" kilo " +
"and earns " + this.salary + " dollar.";
};
これらは、元のコードの使用と同様に使用できます
var person = new Person(50,90);
var employee = new Employee(43,80,50000);
console.log(person.getInfo());
console.log(employee.getInfo());
ただし、Employeeのコンストラクターはpersonのコンストラクターに非常に似ており、プロトタイプの唯一の関数がオーバーライドされているため、ここでは継承を使用してもあまり得られません。ポリモーフィックデザインの力は、動作を共有することです。
この他の答え で説明したように、多型にはさまざまな解釈があります。
私が今まで読んだ主題に関する最良の説明は、有名なタイプ理論家 Luca Cardelli による記事です。この記事の名前は タイプ、データの抽象化、多態性について です。
Cardelliは、この記事でいくつかのタイプのポリモーフィズムを定義しています。
おそらくJavaScriptでは、静的型システムでは従来の型のポリモーフィズムがより顕著であるのに対し、JavaScriptでは動的型システムがあるため、ポリモーフィズムの効果を見るのが少し難しくなります。
そのため、たとえば、JavaScriptでのコンパイル時にメソッドまたは関数のオーバーロードや自動型強制はありません。動的言語では、これらのほとんどのことを当たり前のことと考えています。言語の動的な性質のため、JavaScriptのパラメトリック多態性のようなものも必要ありません。
それでも、JavaScriptにはJavaのような他のオブジェクト指向プログラミング言語で通常行う方法と同様の方法で、サブタイプポリモーフィズム(上記のCardelliによる包含ポリモーフィズムとして分類)の同じ概念をエミュレートする型継承の形式がありますまたはC#(上記で共有した別の回答で説明したとおり)。
動的言語で非常に典型的な多型の別の形式は、 ダックタイピング と呼ばれます。
ポリモーフィズムがオブジェクト指向プログラミングにのみ関係していると考えるのは間違いです。他のプログラミングモデル(関数型、手続き型、ロジックなど)では、型システムにさまざまな形の多型があり、おそらくOOPにしか使用されていないものに少し馴染みがありません。
ポリモーフィズムは、ソフトウェアの多くの優れた属性を促進します。とりわけ、モジュール性と再利用性を促進し、型システムをより柔軟で順応性のあるものにします。それがなければ、型について推論するのは本当に難しいでしょう。ポリモーフィズムは、パブリックインターフェイスを満たす限り、1つのタイプを他の互換性のあるタイプに置き換えることができるため、情報の隠蔽とモジュール性も促進されます。
答えるのは簡単ではありません。異なる言語には異なる実装方法があります。 JavaScriptの場合、前述のように、 プロトタイプ継承 を使用して型階層の形式で具体化され、ダックタイピングを使用してそれを悪用することもできます。
主題は少し広く、1つの投稿で2つの多くの質問を開きました。おそらく、Cardelliの論文を読んで開始し、言語やプログラミングパラダイムに関係なくポリモーフィズムを理解しようとするのが最善です。その後、理論的な概念と、JavaScriptのような特定の言語がそれらのアイデアを実装するために提供するものとの関連付けを開始します。
ポリモーフィズムは、型の等価性の条件を緩和することにより、(重要な)静的型の安全性を失うことなく、静的型システムをより柔軟にします。型エラーが含まれていない場合にのみプログラムが実行されるという証拠が残っています。
ポリモーフィック関数またはデータ型は、より多くのシナリオで使用できるため、モノモーフィック関数またはデータ型よりも一般的です。この意味で、ポリモーフィズムは、厳密に型指定された言語での一般化の概念を表しています。
Javascriptには脆弱で動的な型システムがあります。このような型システムは、1つの型のみを含む厳密な型システムと同等です。このような型は、巨大な共用体型(疑似構文)と考えることができます。
type T =
| Undefined
| Null
| Number
| String
| Boolean
| Symbol
| Object
| Array
| Map
| ...
すべての値は、実行時にこれらのタイプの選択肢のいずれかに関連付けられます。また、Javascriptの型は弱いため、すべての値はその型を何度でも変更できます。
型の理論的な観点から、型が1つしかないことを考慮すると、Javascriptの型システムにはポリモーフィズムの概念がないと確信できます。代わりに、ダックタイピングと暗黙的な型強制があります。
しかし、これはプログラムの型について考えることを妨げないはずです。 Javascriptには型がないため、コーディングプロセス中に型を推測する必要があります。私たちの心は行方不明のコンパイラーに代わる必要があります。つまり、プログラムを見るとすぐに、アルゴリズムだけでなく、基礎となる(多態的な)型も認識しなければなりません。これらのタイプは、より信頼性が高く堅牢なプログラムを構築するのに役立ちます。
これを適切に行うために、多型の最も一般的な症状の概要を説明します。
パラメトリック多相性では、型はまったく関係ないため、異なる型は互換性があると言われています。パラメトリック多相型の1つまたは複数のパラメーターを定義する関数は、対応する引数について何も知らないでください。ただし、すべての型に採用できるため、すべて同じように扱います。このような関数は、データの一部ではない引数のプロパティでのみ機能するため、これは非常に制限されています。
// parametric polymorphic functions
const id = x => x;
id(1); // 1
id("foo"); // "foo"
const k = x => y => x;
const k_ = x => y => y;
k(1) ("foo"); // 1
k_(1) ("foo"); // "foo"
const append = x => xs => xs.concat([x]);
append(3) ([1, 2]); // [1, 2, 3]
append("c") (["a", "b"]); // ["a", "b", "c"]
アドホックポリモーフィズムは、異なるタイプは特定の目的のためにのみ同等であると言います。この意味で同等であるためには、型はその目的に固有の一連の関数を実装する必要があります。アドホックポリモーフィックタイプの1つ以上のパラメーターを定義する関数は、各引数に関連付けられている関数のセットを知る必要があります。
アドホックポリモーフィズムにより、関数はより大きなタイプのドメインと互換性があります。次の例は、「マップオーバー」の目的と、タイプがこの制約を実装する方法を示しています。関数のセットの代わりに、「マッピング可能な」制約には単一のmap
関数のみが含まれます。
// Option type
class Option {
cata(pattern, option) {
return pattern[option.constructor.name](option.x);
}
map(f, opt) {
return this.cata({Some: x => new Some(f(x)), None: () => this}, opt);
}
};
class Some extends Option {
constructor(x) {
super(x);
this.x = x;
}
};
class None extends Option {
constructor() {
super();
}
};
// ad-hoc polymorphic function
const map = f => t => t.map(f, t);
// helper/data
const sqr = x => x * x;
const xs = [1, 2, 3];
const x = new Some(5);
const y = new None();
// application
console.log(
map(sqr) (xs) // [1, 4, 9]
);
console.log(
map(sqr) (x) // Some {x: 25}
);
console.log(
map(sqr) (y) // None {}
);
他の答えはすでにサブタイプ多型をカバーしているので、スキップします。
構造多型では、異なるタイプは同等であり、同じ方法で同じタイプの構造を含む場合、1つのタイプは他のタイプのすべてのプロパティを持ちますが、追加のプロパティが含まれることがあります。そうは言っても、構造多型はコンパイル時にアヒルの型付けであり、確かに追加の型安全性を提供します。しかし、2つの値がいくつかのプロパティを共有しているという理由だけで同じ型であると主張することにより、値のセマンティックレベルを完全に無視します。
const weight = {value: 90, foo: true};
const speed = {value: 90, foo: false, bar: [1, 2, 3]};
残念ながら、speed
はweight
のサブタイプと見なされ、value
プロパティを比較するとすぐに、リンゴとオレンジを実質的に比較しています。
それは何ですか?
ポリ=多く、モーフィズム=形態または行動の変化。
なぜ必要なのか?
プログラミングでは、関数(関数Xなど)のインターフェイスに、さまざまな種類または数のパラメーターを受け入れるのに十分な柔軟性を持たせたい場合に使用します。また、パラメーターのタイプまたは数値の変更に基づいて、関数Xの動作を変更することもできます(モーフィズム)。
使い方?
X関数の複数の実装を作成します。各実装は、異なるパラメータータイプまたはパラメーター数を受け入れます。パラメーターのタイプまたは数に基づいて、コンパイラーは(実行時)何らかのコードからXが呼び出されたときに実行されるXの実装を決定します。
javascriptでこの多態的な動作をどのように達成できますか?
JSは型付き言語ではないため、ポリモーフィズムなどのOOP概念を使用することを意図したものではありません。ただし、JSの新しいバージョンにはクラスが含まれるようになり、ポリモーフィズムがJSでも意味を持ち始める可能性があります。他の回答は、いくつかの興味深い回避策を提供します。
JavaScriptはインタープリター言語であり、コンパイルされた言語ではありません。
コンパイル時ポリモーフィズム(または静的ポリモーフィズム)コンパイル時ポリモーフィズムは、Java、c ++でオーバーロードするメソッドにすぎません
そのため、javascriptではメソッドのオーバーロードはできません。
しかし、動的(実行時)ポリモーフィズムは、実行時に存在するポリモーフィズムであるため、javascriptでメソッドのオーバーライドが可能です。
別の例はPHPです。
ポリモーフィズムとは、異なるオブジェクトで同じメソッドを呼び出す能力を意味し、各オブジェクトが異なる方法で応答することをPOLYMORPHISMと呼びます。
function Animal(sound){
this.sound=sound;
this.speak=function(){
return this.sound;
}
}
//one method
function showInfo(obj){
console.log(obj.speak());
}
//different objects
var dog = new Animal("woof");
var cat = new Animal("meow");
var cow = new Animal("humbow");
//responds different ways
showInfo(dog);
showInfo(cat);
showInfo(cow);