「カプセル化」のかなり狭い定義を使用しているようです。あなたがカプセル化を「データとメソッドを結合すること」と定義していると推測するのは正しいでしょうか?</p>
私が間違っている場合は、この投稿の残りの部分を無視してください。
カプセル化はあいまいな用語ではありません。実際、これは国際標準化機構によって定義されています。ISO の Open Distributed Processing の参照モデル - 次の 5 つの概念を定義します。
エンティティ: 興味のある具体的または抽象的なもの。
オブジェクト: エンティティのモデル。オブジェクトは、その動作によって特徴付けられ、二重に、その状態によって特徴付けられます。
動作 (オブジェクトの): 発生する可能性がある一連の制約を伴うアクションのコレクション。
インターフェース: オブジェクトの相互作用のサブセットと、それらがいつ発生するかに関する一連の制約から構成される、オブジェクトの動作の抽象化。
カプセル化: オブジェクトに含まれる情報は、オブジェクトがサポートするインターフェースでの相互作用を通じてのみアクセスできるという特性。
さらに、自明の提案を行うことができます。一部の情報はこれらのインターフェイスを介してアクセスできるため、一部の情報はオブジェクト内で非表示にしてアクセスできないようにする必要があります。そのような情報が示す特性は情報隠蔽と呼ばれ、モジュールは難しい決定と変更される可能性のある決定の両方を隠すように設計されるべきであると主張することで Parnas が定義した、優れたコンピューティング論文の 1 つを参照してください。
http://www.cs.umd.edu/class/spring2003/cmsc838p/Design/criteria.pdf
情報が隠されているのはデータだけではないことに注意することが重要です。変更が難しい、または変更される可能性が高いのは、オブジェクトに関連付けられた動作のサブセットです。
あなたの投稿では、オブジェクト指向と関数型プログラミングのカプセル化の違いはデータ管理に起因すると言っているようですが、少なくとも ISO と Parnas によると、データ管理はカプセル化の鍵ではありません。したがって、関数型プログラミングのカプセル化がOOのカプセル化と異なる必要がある理由がわかりません。
さらに、関数型プログラミングはカプセル化を提供すると投稿で述べていますが、「…データ構造ではなくメソッドによって」です。これは、絶対的なものではなく、規模の違いだと思います。「データ構造」ではなく「オブジェクト」という言葉を使用する場合 (誤解があれば教えてください)、OO のオブジェクトによるカプセル化と関数型プログラミングのメソッドによるカプセル化に重要性を見出しているようです。
しかし、上記の ISO の定義によれば、オブジェクトとは私がモデル化したいものすべてです。したがって、それらのクラスの一部がパッケージのインターフェース (つまり、パッケージのパブリック クラス) に寄与し、一部が情報隠蔽 (パッケージ内のプライベート クラス) である限り、クラスはパッケージ内にカプセル化できます。
同様に、メソッドはクラス内にカプセル化されます。一部のメソッドはパブリックであり、一部のメソッドはプライベートです。これを一段低くして、McCabian コードのシーケンシャル シーケンスがメソッド内にカプセル化されていると言うことができます。それぞれが、カプセル化された領域内にカプセル化されたノードのグラフを形成します。そして、これらすべてのグラフがグラフ スタックを形成します。したがって、関数型プログラミングは関数/ファイル レベルでうまくカプセル化されている可能性がありますが、これは OO のメソッド/クラス グラフと何ら変わりはなく、OO のクラス/パッケージ グラフとも本質的に違いはありません。
また、Parnas が上で使用している単語に注意してください: 変更。情報隠蔽は、将来の困難な設計上の決定の変更など、潜在的なイベントに関係しています。OO の強みはどこにあるのかと尋ねます。確かにカプセル化は OO の強みですが、「カプセル化の強みはどこにあるのか」という疑問が生じます。その答えは、非常に明快なものの 1 つです。それは、チェンジ マネジメントです。特に、カプセル化により、変更の最大の潜在的な負担が軽減されます。
ここでは、「潜在的な結合」の概念が役立ちます。
「カップリング」自体は、「あるモジュールから別のモジュールへの接続によって確立される関連付けの強さの尺度」として定義されています。
http://www.research.ibm.com/journal/sj/382/stevens.pdf
また、論文が言うように、「モジュール間の接続を最小限に抑えることで、変更やエラーがシステムの他の部分に伝播する経路も最小限に抑えられるため、ある部分の変更が原因である悲惨な「リップル」効果が排除されます。別の場所でエラーが発生し、他の場所で追加の変更が必要になり、新しいエラーが発生するなど。」</p>
ただし、ここで定義されているように、簡単に解除できる制限が 2 つあります。まず、結合はモジュール内接続を測定しません。これらのモジュール内接続は、モジュール間接続と同じくらい多くの「リップル」効果を引き起こす可能性がありますただし、これは結合が定義された要素間の接続 (つまり、ラベルまたはアドレスへの参照) に関して定義されていません)。第二に、モジュールが接続されている、または; 結合の定義には、Parnas が話す潜在的な変化を管理する余地はほとんどありません。
これらの問題は両方とも、潜在的な結合 (プログラムのすべての要素間で形成可能な接続の最大数) の概念によって、ある程度解決されます。たとえば、Java では、パッケージ内のパッケージ プライベート (デフォルトのアクセサー) であるクラスは、その上で接続を形成できません (つまり、リフレクションにもかかわらず、外部のクラスはそれに依存できません)。それに依存関係があります。この public クラスは、現時点で他のクラスが依存していなくても、潜在的な結合に寄与します。将来、設計が変更されたときにクラスが依存する可能性があります。
カプセル化の強さを確認するには、負担の原則を検討してください。負担の原則には 2 つの形式があります。
ストロング フォームでは、エンティティのコレクションを変換する負荷は、変換されたエンティティの数の関数であると述べています。弱形式は、エンティティのコレクションを変換する際の潜在的な最大負荷は、変換されるエンティティの最大潜在数の関数であると述べています。
ソフトウェア システムを作成または変更する負担は、作成または変更されたクラスの数の関数です (ここでは、オブジェクト指向システムを想定して「クラス」を使用し、クラス/パッケージ レベルでのカプセル化に関係しています。関数型プログラミングの関数/ファイルレベルに関心がありました)。(「負担」とは、通常、最新のソフトウェア開発のコスト、時間、またはその両方であることに注意してください。) 特定の変更されたクラスに依存するクラスは、変更されたクラスに依存しないクラスよりも影響を受ける可能性が高くなります。 .
変更されたクラスが課す可能性のある最大の負荷は、それに依存するすべてのクラスに影響を与えることです。
したがって、変更されたクラスへの依存関係を減らすと、その更新が他のクラスに影響を与える可能性が減り、そのクラスが課す可能性のある最大の負担が減ります。(これは、「構造化された設計」論文の再記述にすぎません。)
したがって、システム内のすべてのクラス間の潜在的な依存関係の最大数を減らすと、特定のクラスへの影響が他のクラスへの更新を引き起こす可能性が減少し、したがってすべての更新の潜在的な最大負荷が減少します。
したがって、カプセル化は、すべてのクラス間の潜在的な依存関係の最大数を減らすことにより、負担の原則の弱い形式を緩和します。これはすべて、プログラムを構造化する論理的手段として潜在的な結合を使用して、そのような主張を数学的に証明しようとする「カプセル化理論」によってカバーされています。
ただし、「カプセル化はすべての価値のあるコードの鍵ですか?」と尋ねる場合は注意してください。答えは間違いなく「いいえ」です。価値のあるすべてのコードの鍵は 1 つではありません。カプセル化は、特定の状況では、コードの品質を向上させて「価値のある」ものにするツールにすぎません。</p>
また、「…カプセル化は、オブジェクトの柔軟な拡張に対する障壁になる可能性があります」とも書いています。はい、確かに可能です。実際、変更が困難または変更される可能性のあるオブジェクトの設計上の決定を拡張することに対する障壁になるように設計されています。ただし、これは悪いことだとは考えられていません。別のアプローチは、すべてのクラスを公開し、プログラムに最大の潜在的な結合を表現させることです。しかし、負担の原則の弱い形は、更新がますます費用がかかるようになると述べています。これらは、拡張に対する障壁を測定するためのコストです。
最後に、カプセル化とセマンティクスの興味深い比較を行います。あなたの意見では、オブジェクト指向のセマンティクスがその大きな強みです。私もセマンティストではありません (善良なラムゼイ氏が彼のコメントで言及するまでは、そのような言葉が存在することさえ知りませんでした) が、あなたが意味するのは「セマンティクス」の意味であると推測します。単語の意味の解釈」であり、非常に基本的には、woof() メソッドを持つクラスは Dog と呼ばれるべきです。
このセマンティクスには確かに大きな強みがあります。
私が興味を持っているのは、セマンティクスをカプセル化と比較して勝者を探すことです。私はあなたがそれを見つけるとは思えません。
私の意見では、カプセル化の動機には 2 つの力があります。セマンティックと論理です。
セマンティック カプセル化とは、カプセル化されたノード (一般的な用語を使用する場合) の意味に基づくカプセル化を意味します。したがって、「アニマル」と「ミネラル」という名前の 2 つのパッケージがあることを伝え、Dog、Cat、および Goat の 3 つのクラスを指定し、これらのクラスをどのパッケージにカプセル化するかを尋ねると、次のようになります。システムのセマンティクスは、3 つのクラスが「鉱物」ではなく「動物」パッケージ内にカプセル化されていることを示していると主張するのは完全に正しいでしょう。
ただし、カプセル化のもう 1 つの動機はロジックであり、特に前述の潜在的な結合の研究です。カプセル化理論は、実際には、潜在的な結合を最小限に抑えるために、いくつかのクラスをカプセル化するために使用する必要があるパッケージの数の方程式を提供します。
私にとって、カプセル化は全体として、このセマンティック アプローチと論理的アプローチの間のトレードオフです。これにより、プログラムがセマンティックに理解しやすくなる場合は、プログラムの潜在的な結合が最小値を超えることを許可します。しかし、膨大で無駄なレベルの潜在的な結合は、それが意味的にどれほど明白であっても、プログラムを再構築する必要があるという警告になります。
(そして、良きミスター・ラムジーがまだ読んでいるなら、あなたまたはあなたのセマンティストの友人が、私がここで使用している「セマンティクス」フェーズについて、より適切な言葉を教えてくれませんか? より適切な用語を使用した方がよいでしょう。)
よろしく、エド。