Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

第3回勉強会 オブジェクト指向

5,020 views

Published on

はこだてIKA 第3回夜間勉強会で使用した資料です。

Published in: Technology
  • Be the first to comment

第3回勉強会 オブジェクト指向

  1. 1. まじめなオブジェクト指向 はこだてIKA 勉強会 アットウェア 函館ラボ 高橋 哲也
  2. 2. まず最初に・・・前回の講師はオブジェクト指向について「出来れば知っておいた方が良い」と、言っていましたが・・・
  3. 3. 甘い
  4. 4. この場は若手に向けた 勉強会だということを踏まえてあえて言いますが必須です。
  5. 5. どうして?• よく本を見ると書いてある オブジェクト指向のメリットというと• 大規模開発に向いている• 開発効率が良い• メンテナンス性が良い• というのが書いてますが これらを享受するためだけではありません。
  6. 6. • 「オブジェクト指向」というのはプログラムの 設計(実装する際の詳細設計も含む) 設計(実装する際の詳細設計も含む)を 行なうときに必要となる『考え方』 行なうときに必要となる『考え方』です。• 言い換えれば「思想」であり、その思想自体に 優劣があるわけではありません。• ですので、決して 手続き型 < オブジェクト指向 という関係ではないので、間違わないでください。
  7. 7. • プログラミングを行なう際に• オブジェクト指向を知らないから 手続き型で書こう• オブジェクト指向を理解したうえで プロジェクトの特性を加味して 手続き型で書こう• 結果が同じでも意味は全く違います。
  8. 8. • 設計思想を学ぶという行為は 自分がプログラミングを行なう時の 「引き出しを増やす」「選択肢を増やす」ということです。• 「仕事で使わないから関係ないや」 は、自ら選択肢を増やす機会を放棄しているだけです。• つまり、「必須です」と言ったのは 『自分の考え方の幅を広げるだけで 損になることなど何もないのだから 知らないくても良い人などいない』 くても良い人などいない 知らないくても良い人などいない』 という意味です。
  9. 9. でも、絶対に必要ではないんでしょ?• 知りません。• 身に付けてから考えろ。• 「やらない理由」を探すのは 「ただやりたくないだけ」です。
  10. 10. オブジェクト指向は万能ではない• オブジェクト指向でソフトウェア開発の悩みは 全て解消されるわけではありません。• 手続き型での開発の方が適している場面も 当然あります。• 「オブジェクト指向でしか出来ない開発」というのは 存在しません。手続き型も同様です。• 繰り返しになりますが 「選択出来る」ことが大事なのです。
  11. 11. オブジェクト指向が向いている場面• ある程度、大規模な開発案件。 逆に小規模なものは手続き型の方が 向いているケースはあるように思います。• この根拠はコーディング量にあります。 実はオブジェクト指向によるコーディングの方が 純粋なコーディング量は手続き型に比べ 多くなる傾向があります。• コーディング量が少ないもの=良いものとは 言いませんが、必要以上に多いのは やはり考えものです。
  12. 12. あくまでイメージですが、処理量とコーディング量の関係はこのような形に近いのではないかと思います。 コ ー デ オブジェクト指向 ィ ン グ 量 手続き型 処理量
  13. 13. オブジェクト指向が向かない場面• ハードウェアのリソースが極端に限られている。• これは前述のコーディング量にも関係しますが コーディング量が多いというのは それだけ実行時のメモリも圧迫します。• 組み込み系に未だCが多いのも、おそらくこれが 組み込み系に未だC 主な原因じゃないかと思います。 組み込み系Javaもあるにはありますが) Javaもあるにはありますが (組み込み系Javaもあるにはありますが)• 余談:Javaメモリの開放がJVM任せなので 余談:Javaメモリの開放がJVM任せなので Javaメモリの開放がJVM 組み込み畑の人々には嫌われる傾向にあります。
  14. 14. どうやって学ぶ?• 1番手っ取り早いのはプログラムを たくさん書くことです。• 先ほども言いましたが 「思想」ですので、【 「思想」ですので、【 知識 】だけで 身に付くようなものではありません。 【 体得 】してください。
  15. 15. じゃあ、この講義意味無くね?• いきなりプログラミングをして 正しくオブジェクト指向が身に付くわけはありません。• まずは【 知識 】を正しく まずは【 身に付けておくことが重要です。• チーム開発で「オレ流」ほど 周りに迷惑なものはありません。• 本を読むのも非常に有効な手段です。
  16. 16. • オブジェクト指向型言語(Java) を使える オブジェクト指向型言語(Java) = オブジェクト指向を理解している と勘違いしている人が社会人でも多くいます。• 正しく知識を得ないまま突っ走ると 後から矯正する方が大変な場合が多いです。• 勉強をするのはもちろん大事ですが そのやり方も大事なのです。
  17. 17. オブジェクト指向って何?• シンプルで当たり前な疑問だと思いますが なかなか難しい問題だと思います。• オブジェクト指向の3大概念として オブジェクト指向の3 「カプセル化」 「継承」 「ポリモーフィズム(多態性) 「ポリモーフィズム(多態性)」 が存在しますが、これらを全て満たすことが オブジェクト指向プログラミングかと言うと そうではありません。
  18. 18. • 先程も言いましたが「オブジェクト指向」というのは 考え方の1 考え方の1つであり、思想です。• なので、「これをしたらオブジェクト指向」という なので、「これをしたらオブジェクト指向」という 明確な線引きは難しいです。• 強いて言うと、私がソースコードを見て オブジェクト指向を理解しているかどうかを 判断するのはモデリング モデリングが出来ているかどうかです 判断するのはモデリングが出来ているかどうかです 。
  19. 19. モデリングとは• 要はクラス設計にあたるものだと 考えてくれれば問題ないです。• このオブジェクトがこのメソッドを持つのは妥当か• このデータをこのオブジェクトに保持させて良いのか• オブジェクトの単位は適切か• 継承、ポリモーフィズムを用いている場合 その関係性は妥当か• など、どのオブジェクトにどのようなデータや メソッドを持たせるかということを 適切に切り分ける作業をモデリングと言います。• オブジェクト指向の理解を深めることで このモデリングの作業を正しく行えるようになると 個人的には思います。
  20. 20. ガンダムで考えよう• 皆大好きガンダムを例に考えてみましょう。• ガンダムを1つのアプリケーションと 考えてください。• ロボットの制御プログラミング等を やってる方はいったん忘れてください。 そういうの いうのじゃないです。 そういうのじゃないです。
  21. 21. 機能を考える• ガンダムの「指」があります。 この1 この1本の指の持つ機能は何でしょうか?• 「曲げる」と「伸ばす」ですね。
  22. 22. • 次に5本の指を含めた「掌」全体です。 次に5 この機能は何でしょう?• 「握る」と「開く」ですよね。
  23. 23. • 次は「肘」です。• これも「曲げる」と「伸ばす」ですよね。
  24. 24. • 「肩」はどんな機能でしょう? これはちょっと難しいですね。• とりあえず「回す」とでもしておきましょう。
  25. 25. ここまでをプログラムで表現してみます。 • 細かいところは省くとして 「指」というものをひとつのクラスとして考えると 下記のような書き方になります。public class 指 { public void 曲げる() { // 曲げる処理 } public void 伸ばす() { // 伸ばす処理 }}
  26. 26. 次は「掌」。5次は「掌」。5つの指のフィールドが定義されています。 public class 掌 { private 指 オヤユビ = new 指(); private 指 ヒトサシユビ= new 指(); private 指 ナカユビ= new 指(); private 指 クスリユビ = new 指(); private 指 コユビ = new 指(); public void 握る() { オヤユビ.曲げる(); ヒトサシユビ.曲げる(); ナカユビ.曲げる(); クスリユビ.曲げる(); コユビ.曲げる(); } public void 開く() { // 各指を伸ばす処理 } }
  27. 27. 次は肘ですが、これは「指」と似ていますね。public class 肘 { public void 曲げる() { // 曲げる処理 } public void 伸ばす() { // 伸ばす処理 }}
  28. 28. 肩はこのようになります。public class 肩 { public void 回す(int 角度, int 方向) { // 引数の指定値だけ肩を回す処理 }}
  29. 29. そしてこれらの部品を制御する「腕」というクラスを作成します。 public class 腕 { private 肩 カタ = new 肩(); private 肘 ヒジ = new 肘(); private 掌 テ = new 掌(); public void 物を掴む() { カタ.回す(90, 0); // 方向は「前:0」「後:1」とします ヒジ.伸ばす(); テ.握る(); } public void 物を投げる() { カタ.回す(270, 1); カタ.回す(180, 0); ヒジ.伸ばす(); テ.開く(); } }
  30. 30. ついでに「体」も作っておきましょう。 public class 体 { private 腕 ミギウデ = new 腕(); private 腕 ヒダリウデ = new 腕(); // その他にも「腰」とか「頭」とか色々。 // 処理も色々あると思いねぇ。 }
  31. 31. 本筋に戻りましょう• さて、変なプログラムを作ったところで本題に戻ります。• このようにモデリングとはアプリケーション全体の いくつかの機能をオブジェクトとして定義し その中に適切なフィールド、メソッドを作ることを指します。• 例えばですが、この場合「肩」に 指を曲げる() メソッドが 指を曲げる() 定義されていたりすると、あまり好ましくないと言えます。
  32. 32. カプセル化• 各パーツに命令を出すのは 当然パイロットのいる「体(ボディ) 当然パイロットのいる「体(ボディ)」になるわけですが パイロットが物を掴みたいときは「腕」に対して ミギウデ.物を掴む(); ミギウデ.物を掴む(); () と命令をすれば良いわけです。• その中で「肘」がどう制御されているのか 「指」がどういう動きをするのかは意識しません。 「体」は「腕」というクラスには 「物を掴む()」というメソッドと「物を投げる() ()」というメソッドと「物を投げる()」というメソッドが 「物を掴む()」というメソッドと「物を投げる()」というメソッドが 存在しているということを知っているだけです。• 「体」から見えるのは 『 public 』 で宣言されている public メソッド2つだけで、「肩」「肘 メソッド2つだけで、「肩」「肘」「掌」の存在は意識していません。
  33. 33. • さらに言うと物を掴むときの処理も意識しません。 さらに言うと物を掴むときの処理も意識しません。 あくまで呼び出し側( は自分が持つフィールド( あくまで呼び出し側(体)は自分が持つフィールド(腕)に 宣言されている定義しか考えていないのです。• 呼び出し側に「物を掴め」と命令されたときに どういう処理を行なうかは、あくまで命令された 「腕」が把握しているべき内容なのです。• これをカプセル化と呼びます。• カプセル化はオブジェクト指向に限らず 手続き型にも導入出来る概念だと思います。 手続き型にも導入出来る概念だと思います。 実装には苦労すると思いますけど) (実装には苦労すると思いますけど)
  34. 34. • カプセル化によるメリットは数多くあります。 カプセル化によるメリットは数多くあります。 による• 例えばガンダムの「肘」をマグネットコーティングを施した 新型の「新肘」クラスに換装したとします。• この場合、変更となるのは「腕」のみです。 何故なら他の部品は「肘」について 何も意識していないからです。 「掌」も「肩」も「体」も「肘」という存在すら知りません。• 変更が無いということはテストも行わなくて良いということです。 テストケースの修正が不要) (テストケースの修正が不要)
  35. 35. カプセル化のちょっと余談• オブジェクト指向の本を読むと カプセル化=隠蔽すること カプセル化=隠蔽すること という記述が大半ですが これだけでは厳密には正しくありません。• カプセル化の本質はオブジェクト間の 依存度を下げること』 『依存度を下げること』です。• その1つの手段として、隠蔽があるだけです。 その1• その意味で言うと、むしろ 「必要なフィールド・メソッドのみを”公開” 「必要なフィールド・メソッドのみを”公開”すること」 の方が正しいように思います。
  36. 36. 継承• 先程の「指」と「肘」を思い出してください。• どちらも「曲げる」「伸ばす」という機能を 持ったクラスでした。• 同じ機能を持つということは オブジェクト指向の視点で見ると 「似たもの」と分類されます。• 「指」と「肘」に親クラスを作成し 「指」と「肘」に親クラスを作成し 継承関係にしてみましょう。
  37. 37. 「指」と「肘」の共通処理を親クラスへpublic abstract class 関節 { public void 曲げる() { // 曲げる処理 } public void 伸ばす() { // 伸ばす処理 }}public class 指 extends 関節 { // 指の独自フィールド、メソッド}public class 肘 extends 関節 { // 肘の独自フィールド、メソッド}
  38. 38. 2つの継承• 再利用のための継承 → 既に存在するクラスを継承し、拡張する。 → 弱い継承• 汎化のための継承 → 類似クラスの共通な フィールドや処理を括り出す。
  39. 39. 再利用のための継承• 継承のメリットは処理の共通化による コードの集約が大きいです。• ただし、ただ「コードの再利用」のみを目的とした継承は オススメ出来ません。委譲 委譲して、ユーティリティクラスを オススメ出来ません。委譲して、ユーティリティクラスを 作った方が、遥かに利便性が良いはずです。• 「コードの再利用」は 継承による副産物であり あくまでも継承による副産物 あくまでも継承による副産物であり それ自体が目的であってはいけません。 (「継承はコードの再利用のための機能である」と 書いた本も多数存在してますが・・・。) 書いた本も多数存在してますが・・・。)
  40. 40. 汎化のための継承• 複数のクラスに渡って共通して繰り返される処理を 継承するスーパークラスの中に移動させる。• それによりスーパークラスに一般的な作業を行わせ サブクラスには固有な振る舞いだけを実装することが出来ます 。• このスーパークラスに移動するプロセスを「汎化」と言います。• 「再利用のための継承」と大きく異なるところは サブクラスが複数存在するという点で サブクラスが複数存在するという点で サブクラス同士が何らかの 関連性(共通の処理) 関連性(共通の処理)を持っているため、 発生する継承です。
  41. 41. • 『汎化のための継承』を行う場合は 汎化のための継承』 スーパークラスとサブクラスが of(~は~の一種である ~は~の一種である) 「is a type of(~は~の一種である)」 という関係であることに注目するようにしましょう。• これは継承を見直す際に、継承が有効かどうかを 確認する簡単なチェックとしても使えます。 あくまで一般原則としてです です。 *あくまで一般原則としてです。 常に適用出来るとは限りません。• 「is an instance of(~は~の1つの実体である)」と of(~は~の つの実体である) ~は~の1 混同しないように注意しましょう。
  42. 42. 継承の問題点• カプセル化を弱めてしまう。 → スーパークラスの実装を知る必要がある(場合がある) スーパークラスの実装を知る必要がある(場合がある)• スーパークラスに変更が発生した場合の対応が困難。 全てのサブクラスに反映させなければならない(場合がある) → 全てのサブクラスに反映させなければならない(場合がある)• 無秩序に継承を行い、最初は大丈夫だろうと思っていたけど いざ機能を追加・変更しようとしたら、継承の関係で にっちもさっちも身動きが取れないというケースが多々あります 。 サブクラスに対する影響が大き過ぎて) (サブクラスに対する影響が大き過ぎて)
  43. 43. 抽象化という概念• 継承をもっと有効なものとするために 「抽象化」という概念が存在します。• すごく簡単にいうと 「実体(インスタンス) 「実体(インスタンス)を伴わないクラス」 なのですが、この辺を詳しくやりだすとキリが無いので 残念ながら今回は割愛。• Google先生にご教授頂いてください。 Google先生にご教授頂いてください。 (次のポリモーフィズムでも軽く触れます) 次のポリモーフィズムでも軽く触れます)
  44. 44. ポリモーフィズム(多態性)• ある人が思いつきました ガンダムに ズゴックの手を付けたら 結構強いんじゃね? ※参考:ズゴック(シャア専用)
  45. 45. やりましょう
  46. 46. (特別ゲスト:MMRの皆さん)
  47. 47. • お客様というのは(ときに)無茶を言うもの。 お客様というのは(ときに)• 変更内容は現行の「掌」を まるっとズゴックハンドにしろというもの。 まるっとズゴックハンドにしろというもの。• これが全ての「指」を制御する処理が 「肘」、「肩」あたりにも散らばっていたらと思うと 目も当てられません。• とりあえずズゴックの手のようなクラスを実装しましょう。
  48. 48. ズゴックハンドの実装public class ズゴックハンド { private 爪 ツメ1 = new 爪(); private 爪 ツメ2 = new 爪(); private 爪 ツメ3 = new 爪(); public void 握る() { ツメ1.曲げる(); ツメ2.曲げる(); ツメ3.曲げる(); } public void 開く() { // 各爪を伸ばす処理 }}
  49. 49. • あれ?と思いませんか?• そう「掌」と同じメソッドですね。 ただ保持しているフィールドが違うので 実装内容が異なり、先程のように継承は使えません。• こういう場合はインターフェースを使って 抽象化することが有効です。
  50. 50. 「掌」と「ズゴックハンド」に共通のインターフェースをpublic interface 手 { public void 握る(); public void 開く();}public class 掌 implements 手 { // さっきのと同じ}public class ズゴックハンド implements 手 { // さっきのと同じ} • インターフェースを導入するとこのようになります。
  51. 51. インターフェースを使って、「腕」を改修 public class 腕 { private 肩 カタ = new 肩(); private 肘 ヒジ = new 肘(); // private 手 テ = new 掌(); private 手 テ = new ズゴックハンド(); ここを切り換えるだけ public void 物を掴む() { カタ.回す(90, 0); // 方向は「前:0」「後:1」とします ヒジ.伸ばす(); テ.握る(); } public void 物を投げる() { カタ.回す(270, 1); カタ.回す(180, 0); ヒジ.伸ばす(); テ.開く(); } }
  52. 52. • ちょっとふざけた説明をしてしまいましたが オブジェクト指向において インターフェースを用いた抽象化というのは インターフェースを用いた抽象化というのは 非常に重要な要素です。• オブジェクト指向の世界では 実装では無く、インターフェースに対してプログラミングしろ』 『実装では無く、インターフェースに対してプログラミングしろ』 という言葉があるほど、インターフェースは という言葉があるほど、インターフェースは 重要視されているのです。• ↑の言葉は、インターフェースが提供されているのであれば ↑の言葉は、インターフェースが提供されているのであれば 後々の変更に柔軟に対応するために 実装クラスに対してではなく、インターフェースに対して メソッドを呼び出すようにプログラムしなさい。という意味です。• つまり、普段から 掌 テ = new 掌(); とするのではなく 手 テ = new 掌(); とコーディングするように 促しているのです。
  53. 53. 継承とインターフェース• 実は先程説明した「継承」でも インターフェースと同様の記述が可能です。• 例えば (); 関節 オヤユビ = new 指(); という書き方も出来るのです。• つまり、継承を用いてもポリモーフィズムは 実現出来るということです。 というのはインターフェースも継承の一種なので) (というのはインターフェースも継承の一種なので)
  54. 54. • が、実際の開発の現場で、ポリモーフィズムの が、実際の開発の現場で、ポリモー 実際の開発の現場で、ポリモ 実現方法として用いられるのは 圧倒的にインターフェースです。• 何故だろうという話になると思いますが 端的に結論だけ言いますと、 「継承を使わなくて済む」からです。 「継承を使わなくて済む」からです。• 別に継承を毛嫌いしているわけでも 何でもないのですが、継承というのは 何でもないのですが、継承というのは それほど慎重に扱った方が良いものなのです。 それほど慎重に扱った方が良いものなのです。
  55. 55. オブジェクト指向型言語• 代表されるのはやはりJavaかと。 代表されるのはやはりJavaかと。 Java• Javaはオブジェクト指向を学習するには Javaはオブジェクト指向を学習するには 非常に適した言語だと思います。• ただし、最初にも言いましたが Javaでプログラミング出来る Javaでプログラミング出来る =オブジェクト指向が身に付いている ではありませんので、気を付けましょう。• 「オブジェクト指向型言語」という言葉の意味は オブジェクト指向の概念を言語仕様として サポートしている、というだけです。 手続き型でだって書けます) (手続き型でだって書けます)
  56. 56. 最後に• 一気にオブジェクト指向の概要を 駆け抜けてきましたが、いかがでしたか?• 正直サッパリわからんだろうなと思います。 正直サッパリわからんだろうなと思います。 ろうなと• 最初にも言いましたが 「考え方」というのは【 「考え方」というのは【 体得 】するものです。 覚えるものではありません。• 難しいとは思いますが、ちゃんと身に付ければ プログラムを行う時の視点が変わっていることに 気付くと思います。• 頑張ってください。

×