| At line 1 changed 2 lines |
| 私は単なるエンジニアであって学者や研究者ではないため、ここに書いてある内容は科学的に吟味されたものではありません。\\ |
| が、普段の仕事の中で気付いた合理性のある内容だと思っています。 |
| !!オブジェクト指向を上手に活かすために |
| ここに書いたのは、私が設計・実装したJavaのフレームワーク開発を主に通じて理解したオブジェクト指向の原理原則です。\\ |
| 私は単なるエンジニアであって学者や研究者ではない上に、オブジェクト指向について誰かから教わった経験も無いため、ここに書いてある内容は科学的に吟味されたものではありません。\\ |
| しかし、普段の仕事の中で気付いた合理性のある内容だと考えています。オブジェクト指向言語を日常使ってはいても、オブジェクト指向そのものをみっちりと学習したことがない人にとって特に役立つ内容だと思います。 |
|
| At line 4 changed one line |
| オブジェクト指向の説明として良く出てくるのが、 |
| オブジェクト指向の最初の説明として良く出てくるのが、 |
| At line 9 changed one line |
| これらはオブジェクト指向の特徴を確かに言い表していますが、オブジェクト指向的な設計や実装をするための役に立たないとytpは考えています。少なくとも初心者にとっては百害有って一理無しです。 |
| これらはオブジェクト指向の特徴を確かに言い表していますが、オブジェクト指向的な設計や実装を初学者が理解するための役に立たないとytpは考えています。少なくとも初心者にとっては百害有って一利無しです。\\ |
| これから説明するオブジェクト指向に関する原則は、実際の開発現場で皆さんが実践することを目的に書いています。つまり、 |
| *開発現場で役立つオブジェクト指向の本質を解き明かす |
| ために書きました。\\ |
| \\ |
| オブジェクト指向設計に関しては__デザインパターン__という形で様々な本が書かれていますが、パターンは有用ではあるものの全部を一々覚えてはいられません。そもそもパターンというのは、オブジェクト指向の本質を理解した人が設計した有用な常套手段に名前を付けたものです。 |
| *パターンは囲碁で言う__定石__ |
| です。しかし、 |
| *定石には必ず理由があり、それらの根底には__共通する原理原則__がある |
| のです。\\ |
| このサイトでは、オブジェクト指向設計における原理原則を記述しています。つまり、 |
| *定石を産み出すための原理原則 |
| です。囲碁で言えば__手筋(てすじ)__が近いでしょうか。\\ |
| これを理解してしまえばパターンのみに頼ることなく正しい設計にたどり着けると私は考えています。しかしパターンを否定しているのでは決してありません。 |
| *パターンの奥に隠れた__本質(原理原則)を理解する__ |
| ことが大切だと考えています。\\ |
| At line 11 changed 2 lines |
| !!クラスを見つけるのがオブジェクト指向設計 |
| オブジェクト指向にはクラスが必要です。オブジェクト指向的に設計しようとすることはクラスを見つけることに他なりません。 |
| !!オブジェクト指向の利点 |
| オブジェクト指向で開発すると何がいいのでしょうか? 一言で言うと、 |
| *1箇所直せばみな直る |
| です。\\ |
| 実はオブジェクト指向は、最初にコードを書く時の生産性は手続き型に較べて低いのです。しかし、 |
| #開発中あるいは開発後に仕様変更または仕様ミスがあって修正する |
| #別のシステムでの部品を流用する |
| ような場合に威力を発揮します。つまり、 |
| #保守性が高い |
| #再利用性が高い |
| という特徴があるのです。\\ |
| そのため、 |
| *徹底したオブジェクト指向で開発されたシステムは総合的な生産性が高い |
| と言えます。\\ |
| At line 14 changed 12 lines |
| !!AクラスとBクラスが異なるクラスとして必要な理由は何? |
| クラスを見つけるというのはつまりクラスを定義することですが、では、AクラスとBクラスという2つの異なるクラスが必要になる時の理由は何でしょうか? |
| #処理が異なる |
| #責務が異なる |
| #データ構造が異なる |
| 正解は「データ構造が異なる」です。\\ |
| クラスの根本は、構造体(データ構造)とそれを扱う処理(関数orメソッド)を一体化させたものです。 |
| 次のリンクはSunのJava入門のページですが、そこにある図を参照して下さい。 |
| [What Is an Object?|http://download.oracle.com/javase/tutorial/java/concepts/object.html]\\ |
| Fieldsというのが構造体のことで、その周りをMethods(処理)が取り巻いています。この図は、クラスを基に生成されたオブジェクトの概念を書いたものですが、オブジェクトの設計図となるクラスの定義も同様な考え方です。\\ |
| この図からも解るように、データ構造を持たないクラスはそもそもクラスとして機能しません。クラスの原理に反するからです。\\ |
| ですが、データ構造を持たないクラスをJavaなどの言語では定義出来てしまうため、単なる関数を定義しただけのclassをクラスと勘違いしている設計者/プログラマーが大勢います。 |
| !!オブジェクト指向はなぜ難しいか |
| 特に最近は関数型指向と言って手続き型へ回帰するほど、オブジェクト指向を回避する傾向が見られます。\\ |
| オブジェクト指向はなぜそれほど難しいのでしょうか?\\ |
| いくつか理由は考えられますが、以下の3点が大きいのではないかと思います。\\ |
| #顧客から要求されるのは処理であってデータ構造ではないため、データ構造を正しく定義出来ないから。 |
| #オブジェクト指向言語は手続き型言語の延長線上にあり、手続き型でも書けてしまうから。(特にJavaの場合は) |
| #RDBとの相性がとても悪く、筋の悪いO/Rマッパーを使うと処理とデータ構造が分離されて結局手続き型になってしまうから。\\ |
| この相性の悪さをインピーダンスミスマッチと言います。どう対応すればいいのかを[関数とユーティリティクラスは禁止]で詳しく書いています。\\ |
| At line 27 changed 24 lines |
| !!責務がクラスを決めるのではないのか? |
| クラスは「責務」によって定義されるといくつかの解説書には書いてありますが、これは誤りだと私は考えています。\\ |
| 責務という言葉を言い換えると「しなければならないこと」「出来なければならないこと」となります。クラスを利用する側から見るとそのクラスが何を出来るか(してくれるか)は確かに重要です。\\ |
| ですがそれは使う側から見た場合であって、設計する人はそれだけではクラスを定義出来ません。一つ例を出します。\\ |
| !!「ジュース売り」という責務 |
| 「ジュース売り」という責務を考えてみます。\\ |
| ジュース売りがしなければならないことは次のような事です。 |
| #注文を聞く |
| #金額を伝える |
| #お金をもらう |
| #品物とお釣りを渡す |
| では、この責務を請け負えるモノは何が考えられるでしょうか?\\ |
| !!ジュース売りを請け負えるモノとは? |
| *人間 |
| *自動販売機 |
| ジュース売りを請け負えるモノとして少なくともこの2つが考えられます。将来的には「ロボット」も入ってくるかもしれません。\\ |
| つまり責務が決まったからと言ってそのモノまでは決められないのです。\\ |
| これは当然で、「何が出来るのか」というのは処理の規定であってデータ構造、つまりそのモノの状態は関係無いからです。\\ |
| Javaなどでは「Interface」として定義するのが責務です。Interfaceはメソッドを規定するだけで中身は実装者任せです。まさに、責務は決めるがモノは決めないという機能です。ちなみに私はInterfaceのことを責務ではなく「役割」と呼ぶようにしています。 |
| !!みんななぜ間違うのか? |
| 世間ではクラスと思われているものが実は誤りである。なぜそうなってしまうのでしょうか?\\ |
| クラスを設計する際、その基となるのは顧客からの要求です。要件と呼ばれます。この要件は、「xxxがしたい」「が出来るようになりたい」という実務処理の記述です。言ってしまえば役割を列挙したものです。\\ |
| 役割というのは上で書いたように処理に過ぎません。クラスとして必要なデータ構造はそれだけでは出て来ません。\\ |
| そのため、オブジェクト指向に不慣れな設計者・実装者はその要件(処理)だけを頼りに開発してしまいます。データ構造を考えずに処理だけを追いかけてしまうのです。これが誤りの根本です。 |
| オブジェクト指向をきちんと理解できていない人が雑誌やWebなどで誤った説明をしているのを見るのはとても複雑な気持ちです。悪気は無いのでしょうが、うまく使いこなせない人を増やす結果になっています。\\ |
| そのような人たちは次の点をまず理解して欲しいと思います。 |
| *処理ではなく、データ構造をまず共通化する。\\ |
| [privateメソッド禁止]で詳しく書いています。 |
| |
| !!クラス図の読み方 |
| このサイトでは、UML(Unified Modeling Language)のクラス図(Class Diagrams)がたくさん出て来ます。ご存じない人のためにその読み方を簡単に説明します。次の3つがあります(UMLの定義ではこれ以外もあります)。\\ |
| #関連 |
| #実現 |
| #汎化 |
|
| !関連 |
| [association.png]\\ |
| 「独立したAクラスとBクラスがお互い相手を参照する」という関係を表します。「バイク本体とタイヤ」のような関係です。タイヤはバイクの部品ですが、あるタイヤを色々なバイクに取り付けることが可能です。 |
| *このバイクの部品として使っているタイヤ |
| *このタイヤを利用しているバイク |
| という双方向の関係が成立します。\\ |
| 関連を記述する場合は |
| *多重度(カージナリティ:cardinality) |
| を省略してはいけません。これが記述されていないと、そのモデルが扱う業務の目的を理解できないからです。\\ |
|
| !実現 |
| [implement.png]\\ |
| 「Mインタフェースの振る舞いをCクラスが具体化(実装)している」という関係を表します。振る舞いの型(呼び出し名、パラメータ、戻り値)だけをインタフェースでは定義し、その具体化(実装)はCクラス側に任せます。 |
| *インタフェースは「役割」 |
| と理解して下さい。\\ |
| 例えば自動車と飛行機の役割は「乗り物」です。この場合、乗り物インタフェースを実現(実装)する形で自動車クラスと飛行機クラスを設計します。 |
|
| !汎化 |
| [generalize.png]\\ |
| 「EとFの性質の共通部分を抜き出してDとした」関係のことです。例えば「ワゴン車とセダンを自動車と呼ぶ」という関係です。「継承」とも呼ばれます。 |
| *ワゴン車は自動車を継承している。 |
| また「__is a の関係__」とも言われます |
| * E is a D. |
| *ワゴン車は自動車である。(自動車として扱える) |
|
| !!集約は使わない |
| UMLの産みの親「Three Amigos」の一人であるジム・ランボーは、 |
| *集約はプラセボ(プラシーボ)効果である |
| と言いました。つまりその効果は「気のせい」で、有用性は無いという意味です。\\ |
| 最近まで私は__関連__を使わずに__集約__のみで書いていたのですが、色々迷って考えた結果この逆の結論に至りました。モデルを表現する際、集約は紛らわしさを助長します。\\ |
| 集約は「has a」の関係と言われ、 |
| *AクラスがBクラスを持つのか? |
| *BクラスがAクラスを持つのか? |
| によって菱形を付けるクラスが入れ換わりますが、関連があるクラス同士は双方向で参照するため、 |
| *どちらも相手を持てる(持つ必要がある) |
| という結果になるのです。そのため集約は意味を成しません。 |
|
| !!このサイトを読む上での注意点 |
| このサイトに書いてある内容には、皆さんのこれまでの常識をくつがえすものが多々あります。今までの常識にとらわれずに読んで下さい。可能ならば頭を白紙の状態にして、書いてある内容を純粋に吟味してみて下さい。皆さんの開発にきっと役立つはずです。\\ |
| \\ |
| それでは次ページから、「本には書いてないオブジェクト指向」の始まりです。\\ |
| !!本には書いてないオブジェクト指向のページ一覧 |
| [クラスとはデータ構造]\\ |
| [責務はクラスではない]\\ |
| [クラスにするもの]\\ |
| [小粒クラス]\\ |
| [リンゴ一個とリンゴ一山は異なるクラス]\\ |
| [関数とユーティリティクラスは禁止]\\ |
| [privateメソッド禁止]\\ |
| [どのメソッドをどのクラスで実装すべきか]\\ |
| [業務シナリオで考える]\\ |
| [インタフェースとは何か]\\ |
| [継承の使いどころ]\\ |
|
| !!ひょっとして出版社の人が居たら |
| このサイトに書いたオブジェクト指向に関しての執筆依頼がもしもあれば喜んでお受けいたします。\\ |
| __田中良浩__: メールアドレスは __tanaka_y__ (ドメインは__ytp.ne.jp__)\\ |