オブジェクト指向プログラミングと関数型プログラミング
1. 序章
今日、最も人気のあるプログラミング言語は、オブジェクト指向または機能パラダイムに基づいています。
このチュートリアルでは、それらの特性を調べて比較します。
2. オブジェクト指向プログラミング
オブジェクト指向言語を定義する最も重要な構成要素はオブジェクト自体です。オブジェクトがなければ、オブジェクト指向について話すことはできません。
オブジェクト指向には複数の形式があります。 たとえば、クラスベースの継承(JavaやC#など)やプロトタイプの継承(JavaScriptなど)。 その上、オブジェクトは多くのコアコンセプトを採用しています。 私たちにとって重要なのはカプセル化です。
カプセル化は、オブジェクトにデータと、データを処理する操作が含まれていることを示します。 さらに、純粋なオブジェクト指向言語では、操作(関数)はオブジェクトの外部に存在することはできません。
つまり、オブジェクトはデータに焦点を合わせます。 操作は後になります。
たとえば、Javaは純粋なオブジェクト指向言語です。 一方、JavaScriptやC++はそうではありません。 ラムダ式とメソッド参照でさえ、クラスを定義するための単なる構文糖衣であるため、Javaの純粋なオブジェクト指向の性質を変更しませんでした。
プリミティブ値はオブジェクトではないため、それらが存在すると、理論的にはJavaが不純になります。 ただし、プリミティブ値を削除すると、言語がかなり不便になります。
3. 関数型プログラミング
関数型プログラミングでは、関数は第一級市民です。たとえば、他の関数のパラメーターとして渡すことも、変数に格納することもできます。
関数は引数を取得し、それらに対して操作を行い、通常は結果を返します。 関数には副作用もあります(たとえば、ローカルまたはグローバル状態の変更、I / O操作の実行など)。
ただし、次の2つの特性を持つ純粋関数を使用することをお勧めします。
- 同じ入力に対して、それらは常に同じ出力を持ちます(したがって、それらはどの状態にも依存せず、入力のみに依存します)
- 副作用はありません
これらの属性のために、純粋関数は決定論的で、よりテスト可能であり、他の関数ではるかに使いやすくなっています。
戻り値のない関数は、副作用がある場合にのみ役立つことに注意してください。
理論的には、これはすべて問題ないように聞こえますが、純粋関数のみを備えたアプリケーションはそのような用途にはなりません。 その理由は、副作用がなければ、I / O操作が必要になるため、意味のある出力を生成できないためです。
要約すると、関数型プログラミングはデータではなく操作に焦点を合わせています。
機能言語の例としては、Haskell、 Scala 、Clojure、Erlangなどがあります。
4. 比較
オブジェクト指向プログラミングと関数型プログラミングには異なる基本概念がありますが、それは私たちにとって何を意味するのでしょうか。 彼らはどのくらい違うのですか?
彼らは非常に異なっていることがわかりました。
これは、それらが相互に排他的ではないことを意味します。 機能言語はオブジェクト指向の特性を持つことができ、オブジェクト指向言語は機能特性を持つことができます。これらの言語をマルチパラダイム言語と呼びます。
オブジェクト指向言語と見なされるJavaには、機能的なスタイルのコードを支援するストリームAPIがあります。 同様に、C#にはLINQがあります。
一方、オブジェクトは関数型言語のデータ構造として使用できます。 その上、Scalaにはクラスもあります。
オブジェクト指向言語が関数型プログラミングのファーストクラスのサポートを持っていない場合でも、単一のメソッドで不変オブジェクトとモデル関数をワーカーオブジェクトとして使用してそれを模倣することができます。
同様に、関数型言語では、カプセル化されたデータを操作するオブジェクトを作成できます。言語で変数の再割り当てが許可されている場合、オブジェクトは変更可能です。 それ以外の場合は、不変オブジェクトしか持つことができません。
5. いつ使用するのですか?
OOはデータに重点を置いているため、データモデリングの優れた候補になります。 一方、関数型プログラミングは操作に重点を置いているため、データの処理に使用する必要があります。
実際、Java8はストリームAPIで同じ哲学を使用しています。 データをモデル化するために、クラス、つまりOOの原則を使用します。 そのデータを処理するには、機能的なスタイルで操作をチェーンします。 読みやすくするのは、処理方法ではなく、実行する操作を定義することです。
6. 次に来るパラダイムは何ですか?
ロバートC。 マーティンは、彼のすばらしい本 CleanArchitectureにパラダイムの概要に関する短い章を持っています。 構造的、オブジェクト指向、および関数型プログラミングを次の文に要約します。
構造プログラミングは、制御の直接転送に規律を課します。
オブジェクト指向プログラミングは、制御の間接的な転送に規律を課します。
関数型プログラミングは、割り当て時に規律を課します。
その後、彼は次のように書いています。
これらの3つのプログラミングパラダイムを導入する際に私がかなり意図的に設定したパターンに注意してください。各パラダイムはプログラマーから機能を削除します。 それらのどれも新しい機能を追加しません。 それぞれが、その意図においてネガティブであるある種の追加の規律を課します。 パラダイムは、からに何をするかよりも、何をしないかを教えてくれます。
この問題を見る別の方法は、各パラダイムが私たちから何かを奪うことを認識することです。 3つのパラダイムは一緒に、gotoステートメント、関数ポインター、および割り当てを削除します。 持ち帰る物はありますか?
おそらくそうではありません。 したがって、これらの3つのパラダイムは、私たちが目にする唯一の3つである可能性が高く、少なくとも3つだけが否定的です。 そのようなパラダイムがこれ以上ないというさらなる証拠は、それらがすべて1958年から1968年までの10年以内に発見されたことです。 その後の数十年間、新しいパラダイムは追加されていません。
7. 結論
この短い記事では、オブジェクト指向プログラミングと関数型プログラミングが相互に排他的ではないことを確認しました。 どちらにも長所があり、それらを組み合わせることで、どちらよりも優れたツールを手に入れることができます。