(/ did)Bertrand Meyerは、サブクラス化が「閉じた」モジュールを拡張する唯一の方法だと考えるのはなぜですか?


19

MeyerのObject-Oriented Software Construction(1988)で、彼は次のようにオープン/クローズド原則を定義しています。

  • モジュールがまだ拡張可能であれば、モジュールは開いていると言われます。たとえば、フィールドに含まれるデータ構造にフィールドを追加したり、実行する一連の機能に新しい要素を追加したりすることができます。
  • モジュールは、他のモジュールで使用できる場合、閉じられていると言われます。これは、モジュールに明確に定義された安定した説明(情報隠蔽という意味でのインターフェース)が与えられていることを前提としています。

彼は言い​​続けます:

モジュールを再度開く場合、古いバージョンに依存しているため、すべてのクライアントを再度開いて更新する必要があります。…[この問題]は、モジュールを新しい関数またはデータ要素によって拡張する必要があるたびに発生し、直接および間接クライアントの変更をトリガーします。...設計とプログラミングに対する古典的なアプローチでは、オープンとクローズの両方のモジュールを記述する方法はありません。

このジレンマに対するMeyerの解決策は、既存のクラスを変更してライブラリモジュールを拡張しないことです。代わりに、既存のクラスをサブクラス化する新しいモジュールを作成し、新しいクライアントがその新しいモジュールに依存するようにします。

今、1988年に、私はTurbo PascalとBlankenship Basicでおもちゃ(手続き)プログラムを書いていました、そして、21世紀の専門的な経験はJVM、CLR、および動的言語でしたので、Meyerの意味がわかりません「設計とプログラミングへの古典的なアプローチ」による。

Meyerのクライアントモジュールを再度開く必要がある理由の具体例(より多くのケースを必要とする、より多くのメンバーを含む列挙のswitchステートメント)は十分に合理的なようですが、ライブラリに機能を追加するたびにアサーションを正当化することはほとんどありませんモジュール、すべてのクライアントを更新する必要があります

この主張が1988年に自明であると思われる歴史的な理由はありますか?たとえば、C静的ライブラリに関数またはデータ構造を追加すると、下位互換性のあるAPIでもクライアントを再コンパイルする必要があるようにレイアウトが変更されましたか?または、MeyerはAPIの下位互換性を強制するメカニズムについて本当に話しているだけですか?


3
興味深い質問です!答えは、何らかの方法で抽象データ型とオブジェクト指向データ抽象化の基本的な違いに関連していると感じています。抽象データ型は、モジュラープログラミングの 2つの主要なデータ抽象化メカニズムです(Betrand Meyerが「古典的なアプローチ」と呼んでいるもの")とオブジェクト指向プログラミング(それぞれコメントを読んでください!)。
ヨルグWミットタグ

それ、変だよ。それは現実によって露骨に矛盾しているようです(1988年であっても)。また、彼が提唱したアプローチは、役に立たないモジュールの増殖をもたらすでしょう。

@ dan1111:多重継承へのアプローチを含むがこれに限定されないEiffelの継承へのアプローチは、C ++、Java、C#などとは異なるため、アプローチが異なることは驚くことではありません。結局、彼はオブジェクト指向に関する彼の見解をサポートするために、特にエッフェルを開発しました。
ヨルグWミットタグ

回答:


18

私が知る限り、この質問はバートランド・マイヤー自身によって回答されており、答えは、この声明は正確ではないということです。デザインとプログラミングの古典的なアプローチでは、そこに確かにすることができ、オープンとクローズの両方である書き込みモジュールへの道なり。

これを見つけるには、この本の第2版(9年後に1997年に出版された)を勉強する必要があります。第2版​​の序文によると、

更新ではなく、徹底的な手直しの結果です。元のバージョンの段落は何も変更されていません。(実際にはほとんど1行です。)

特に、あなたを混乱させる声明は消えました。「§3.3の5つの原則」にオープンクローズド原則の章がまだあり、「§14.7継承の概要」にこのトピックの詳細な議論がありますが、初版の声明はもうありません。

代わりに、以前の方法とは対照的に、オブジェクト指向アプローチでより便利で慣用的な方法に焦点を当てています。

継承のおかげで、オブジェクト指向開発者は、以前の方法で可能であったよりもはるかに増分的なソフトウェア開発アプローチを採用することができます...(§3.3)

この二重の要件(オープンとクローズ)はジレンマのように見え、古典的なモジュール構造は手がかりを提供しません。しかし、継承はそれを解決します。クラスは閉じられます。これは、クラスがコンパイルされ、ライブラリに保存され、ベースライン化され、クライアントクラスによって使用される可能性があるためです。しかし、新しいクラスはそれを親として使用し、新しい機能を追加し、継承された機能を再宣言するため、オープンです。このプロセスでは、オリジナルを変更したり、クライアントを妨害したりする必要はありません...(§14.7)

ここでMeyerが「古典的なアプローチ」とはどういう意味なのか不思議に思われるので、これらの説明は§4.7Traditional Modular Structuresにあります。このセクションでは、これらが「ルーチンのライブラリ」と「パッケージ」を意味することを説明します(後者の場合、著者はこの用語はAdaから取られたものであり、この機能を備えた他の言語(CLUのクラスターとModulaのモジュール)に言及しています)。

考えてみると、これらのアプローチはもともと、オープンクローズド原則に準拠したコードの記述を支援することを目的としていませんでした。これにより、著者はやや時期尚早な評価に導かれ、後に第2版で修正されました。


著者が第1版と第2版の間にその声明について特に気が変わったのは、本自体、つまりパートF:メソッドをさまざまな言語と環境に適用することで、答えを見つけることができると思います。この章の著者は、古い言語でオブジェクト指向メソッドを使用する方法について説明します。

Fortranなどの古典的な言語はまったくオブジェクト指向ではありませんが、それらをまだ使用しなければならない人は、これらの古いアプローチの制限内で実行可能な限り多くのオブジェクト指向のアイデアを適用したいかもしれません。

特に、このパートでは、MeyerがCおよびFortranでも継承(いくつかの警告と制限はありますが)を実装する方法を詳細に説明します。

おわかりのように、これは実際に初版からその声明を改訂する必要があります。「古典的なアプローチで...方法はありません」と、それ正確に行う方法の現実的な例を調整する方法を説明することは、事実上不可能です。


おもしろいし、間違いなく第2版を手に入れようとしなければならないが、なぜOOでない「クラシック」ライブラリでさえ、その機能を妨げずに(少なくとも特定の種類の)機能を追加できなかった理由はまだ明らかではないクライアント。
デビッドモールズ

@DavidMolesのことは、それが可能だし、私の答えの最後の部分はそれを説明しており、マイヤー自身が(彼が第2版のためにリワークしたとき)それを実現し、それがどのように行われるかの例さえ与えたことを説明しています。「著者が特に心を変えたのは...」など
gnat

うーん。「バージョン1に置き換わり、下位互換性があり、以下の機能を追加するこのライブラリのバージョン2」は、可能な限り概念的な方法を除いて「継承」とは見えません。
デビッドモールズ

(私にとって、継承とは、バージョン1がまだ存在し、バージョン2によって呼び出されることを意味します。)
デビッドモールズ

@DavidMolesはバージョン2に置き換えられます(ソースコードを変更して再コンパイルするなど)は、「修正のために閉じられた」とは見なされません。Wikipediaの記事でこれを確認できます:「エンティティは、ソースコードを変更せずにその動作を拡張できます...」
gnat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.