1 / 74

DI と AOP を理解しよう

DI と AOP を理解しよう. 【 発表者のプロフィール 】 ・  Toki ・ 個人事業でプログラムの講師をしています ・ 現場指向  genba-oriented.jp. どうして?. ● Spring は、 DI 、 AOP の概念を適用する際に有用な機能を    提供してくれる    →  DI 、 AOP を理解すれば、自ずと Spring が使いたくなる ( はず ) ● DI 、 AOP を理解せずに Spring を使うのは危険    → 多機能さに惑わされ、適切ではない使い方をしてしまう. まずは、「 DI 、 AOP 」を理解しましょう!.

frieda
Télécharger la présentation

DI と AOP を理解しよう

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. DIとAOPを理解しよう 【発表者のプロフィール】 ・ Toki ・ 個人事業でプログラムの講師をしています ・ 現場指向 genba-oriented.jp

  2. どうして? ●Springは、DI、AOPの概念を適用する際に有用な機能を    提供してくれる    → DI、AOPを理解すれば、自ずとSpringが使いたくなる(はず) ●DI、AOPを理解せずにSpringを使うのは危険    → 多機能さに惑わされ、適切ではない使い方をしてしまう まずは、「DI、AOP」を理解しましょう!

  3. DI Dependency Injection 依存性の注入

  4. 何者なの? DIは、設計思想※です ※ 設計思想:プログラムを設計する際の基本方針

  5. 誤:DIは、OOP※に取って代わるもの 正:OOPをベースにした設計思想です ※Object Oriented Progamming:オブジェクト指向プログラミング

  6. 誤:DI=Spring 正:Springは、DIを適用してプログラム   する際の有用なフレームワークです

  7. 誤:DI=DIコンテナ 正:DIコンテナは、 DIを適用したプログラムを動かすときに    一般的に使われる仕組みです

  8. 誤:DI =コードからnew をなくすこと 正:DIコンテナを利用すると、    内部でnewされるので、    結果的に少なくなるだけです。 DIコンテナを使ったとしても、 コード中でnewした方がよいクラスも存在します (DTO※、Value Object※など) ※:ロジックを持たず、データだけを保持するオブジェクト DTOはData Transfer Objectの略語

  9. 誤:DI = 外部ファイルを使う 正:DIを適用したプログラムの   コンフィグレーションの手段の1つとして、   外部ファイルが用いられます

  10. じゃあ・・・ 「DIの設計思想」ってどういうものなの?

  11. 説明のための前提知識 プログラムには、起動後、 アプリケーションとして「機能する」フェーズと、 その前の「準備する」フェーズが存在します。

  12. 起動後のオブジェクトのイメージ 「準備する」 フェーズ 「機能する」 フェーズ xxxxxxxx xxxxxxxx [] [] [] 起動 xxxxxxxx xxxxxxxx [] [] [] [] xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx newして、設定値を入れて、 オブジェクトを参照させて・・・

  13. Webアプリケーションでのイメージ 「準備する」 「機能する」 ・ サーブレットがリクエストを   受け付ける ・ ビジネスオブジェクトが   データを検索する ・ DAOがDBから   データを取得する  ・ サーブレットがHTMLを返す  ・ Tomcatが   サーブレットをロードする ・ ビジネスオブジェクト※1、 DAO※2が作成される ・ サーブレット →    ビジネスオブジェクト →   DAOの参照が形成される 起動 ※1:業務的な処理を行うオブジェクト ※2:データをDBから取得、更新するオブジェクト

  14. 具体例で見ていきましょう 「データ変換プログラム」 変換 B社 ファイル A社 ファイル

  15. 実際のファイル形式 ファイル形式 文字コード:EUC 改行コード:LF CSV(カンマ区切り)形式 ファイル形式 文字コード:Shift JIS 改行コード:CR+LF TSV(タブ区切り)形式 変換 B社用 A社用 ・「会社名」+「_」+「部署名」   ←→ 「お客様名」 ・「値段」 円 ←→ ドル

  16. ファイルのイメージ A社 1000,株式会社東京産業,東京支部,p000111,5000 1001,株式会社東京産業,横浜支部,p000112,3000 ・・・ ※1ドル=130円で換算 B社 1000 株式会社東京産業_東京支部 p000111 38 1001 株式会社東京産業_横浜支部 p000112 23 ・・・ 一行が一注文データ

  17. 処理の流れ(A社からB社への変換) ・ A社のファイルから一行を読み込む ・ A社の注文データを、B社の注文データに変換する ・ B社のファイルに一行を書き出す ・ 上記をファイルの行数分繰り返す

  18. 上司:「A社ファイルから読み込んだ一行から、上司:「A社ファイルから読み込んだ一行から、 A社注文クラスのオブジェクトを      作成するクラスを担当してください。」 Xさん:「わかりました。」

  19. "1000,株式会社東京産業,東京支部,p000111,5000" から、 ※ ゲッター、セッターメソッド クラスのオブジェクトを作成

  20. A社注文クラスのオブジェクトを返す ファイルから一行の文字列を読み込んで返す Xさんの担当 《create》 Yさんの担当

  21. 注文読込()メソッドを実装 public class A社注文リーダー { String 区切文字; ファイルリーダー ファイルリーダー; public A社注文 注文読込() { String 一行 = ファイルリーダー.一行読込(); String[] 文字配列 = 一行.split(区切り文字); A社注文 A社注文 = new A社注文(); A社注文.set注文ID(文字配列[0]); A社注文.set会社名(文字配列[1]); A社注文.set部署名(文字配列[2]); A社注文.set製品ID(文字配列[3]); A社注文.set値段(文字配列[4]); return A社注文; } }

  22. 動作確認 public class 動作確認 { public static void main(String[] args) { A社注文リーダー A社注文リーダー = new A社注文リーダー(); A社注文 A社注文 = A社注文リーダー.注文読込(); System.out.println(A社注文.get注文ID()); System.out.println(A社注文.get会社名()); System.out.println(A社注文.get部署名()); System.out.println(A社注文.get製品ID()); System.out.println(A社注文.get値段()); } } NullPointerException

  23. これらのフィールドをどうやって設定しようか?これらのフィールドをどうやって設定しようか? public class A社注文リーダー { String 区切文字; ファイルリーダー ファイルリーダー; public A社注文 注文読込() { String 一行 = ファイルリーダー.一行読込(); ・・・

  24. 起動後のオブジェクトのイメージ 「準備する」 フェーズ 「機能する」 フェーズ xxxxxxxx xxxxxxxx [] [] [] 起動 xxxxxxxx xxxxxxxx [] [] [] [] xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx newして、設定値を入れて、 オブジェクトを参照させて・・・

  25. 「準備する」 部分 public class A社注文リーダー { String 区切文字; ファイルリーダー ファイルリーダー; public A社注文 注文読込() { String 一行 = ファイルリーダー.一行読込(); String[] 文字配列 = 一行.split(区切り文字); A社注文 A社注文 = new A社注文(); A社注文.set注文ID(文字配列[0]); A社注文.set会社名(文字配列[1]); A社注文.set部署名(文字配列[2]); A社注文.set製品ID(文字配列[3]); A社注文.set値段(文字配列[4]); return A社注文; } } ? 「機能する」 部分

  26. DIは、「準備する」部分を効率よく行うための設計思想DIは、「準備する」部分を効率よく行うための設計思想 目的は 「準備する」部分と「機能する」部分の分離

  27. 分離することで ・ 開発効率があがる ・ 再利用性があがる ・ スパゲティーコード化が抑止される

  28. 「準備する」部分:その1ハードコーディングする「準備する」部分:その1ハードコーディングする public class A社注文リーダー { String 区切文字= ","; ファイルリーダー ファイルリーダー= new LF改行ファイルリーダー(); public A社注文 注文読込() { String 一行 = ファイルリーダー.一行読込(); ・・・

  29. 上司:「A社のファイルは、たまにタブ区切だったり、上司:「A社のファイルは、たまにタブ区切だったり、 CRLF改行のときもあるし・・・      汎用的に作れないかな?」

  30. 「準備する」部分:その2定数クラスを使う public class 定数クラス { public static final String A社_区切文字 = ","; public static final String A社_改行コード = "LF"; ・・・

  31. public class A社注文リーダー { String 区切文字= 定数クラス.A社_区切文字; ファイルリーダー ファイルリーダー; 定数じゃないフィールドは どうすればいいのだろう?

  32. コンストラクタでnew public class A社注文リーダー { String 区切文字= 定数クラス.A社_区切文字; ファイルリーダー ファイルリーダー; public A社注文リーダー() { if (定数クラス.A社_改行コード.equals("LF")) { ファイルリーダー = new LF改行ファイルリーダー(); } else if (定数クラス.A社_改行コード.equals("CRLF")) { ファイルリーダー = new CRLF改行ファイルリーダー(); } } public A社注文 注文読込() { String 一行 = ファイルリーダー.一行読込(); ・・・ もしくは・・・

  33. 「機能する」部分のメソッドの中でnew public class A社注文リーダー { String 区切文字= 定数クラス.A社_区切文字; ファイルリーダー ファイルリーダー; public 注文読込() { if (定数クラス.A社_改行コード.equals("LF")) { ファイルリーダー = new LF改行ファイルリーダー(); } else if (定数クラス.A社_改行コード.equals("CRLF")) { ファイルリーダー = new CRLF改行ファイルリーダー(); } String 一行 = ファイルリーダー.一行読込(); ・・・ ・メソッドが呼ばれる度(=ファイルの行数分)同じnewが呼ばれて無駄 ・「機能する」部分と「準備する」部分が混在すると、  メソッドの責務が曖昧になり、スパゲティコード化につながる

  34. 上司:「新しい改行コード用のクラスを追加するとき、上司:「新しい改行コード用のクラスを追加するとき、      このクラスも修正しないといけないのはよくないなあ。      そもそも、      定数クラスで改行コードを"LF"に設定する時点で、 LF改行ファイルリーダークラスを使うことが      分かってるはずだから、      わざわざこのクラスでnewすることは      ないんじゃないの?」

  35. 「準備する」部分:その3ファクトリ※パターンを使う「準備する」部分:その3ファクトリ※パターンを使う ※ファクトリ:オブジェクトの工場という意味合い public class 定数兼ファクトリクラス { public static String A社_区切文字 = ","; static ファイルリーダー ファイルリーダー = new LF改行ファイルリーダー(); public static ファイルリーダー getファイルリーダー() { return ファイルリーダー; } ・・・ 改行コードを設定するかわりに、 具象クラスを設定するイメージ

  36. public class A社注文リーダー { String 区切文字= 定数クラス.A社_区切文字; ファイルリーダー ファイルリーダー = 定数兼ファクトリクラス.getファイルリーダー(); public 注文読込() { String 一行 = ファイルリーダー.一行読込(); ・・・ 新しい改行コードのクラスが追加されても、 このクラスを修正する必要はない

  37. 動作確認 public class 動作確認 { public static void main(String[] args) { A社注文リーダー A社注文リーダー = new A社注文リーダー(); A社注文 A社注文 = A社注文リーダー.注文読込(); System.out.println(A社注文.get注文ID()); System.out.println(A社注文.get会社名()); System.out.println(A社注文.get部署名()); System.out.println(A社注文.get製品ID()); System.out.println(A社注文.get値段()); } } すると、 FileNotFoundException (ファイルが見つかりません)

  38. Xさん:「そうか、LF改行ファイルリーダークラスがXさん:「そうか、LF改行ファイルリーダークラスが      ファイルを読み込んでるのか。      しかし、どのファイルを読み込んでるのだろう?      ファイルを用意しないといけないの?      僕のクラスとは関係ないのに・・・」 テストするのが億劫になる

  39. 上司:「他のプロジェクトで、A社注文リーダークラスを上司:「他のプロジェクトで、A社注文リーダークラスを      使いたいらいしいんだけど・・・」 他のプロジェクト 「集計プログラム」 Xさんのプロジェクト 「データ変換プログラム」 設定用のクラスを別にすることができないので、 使い回しが困難 再利用性が悪い

  40. 上司:「定数兼ファクトリクラスで、他のクラスの設定値も上司:「定数兼ファクトリクラスで、他のクラスの設定値も      一元して管理したいね。 Xさん、メンテナンスをお願いね。」 Xさん:「(そんなつもりで作ったんじゃないのに・・・)」

  41. 「準備する」部分:その4DIを適用する public class A社注文リーダー { String 区切文字; public void set区切文字(String 区切文字) { this.区切文字 = 区切文字; } ファイルリーダー ファイルリーダー; public void setファイルリーダー(ファイルリーダー ファイルリーダー) { this.ファイルリーダー =ファイルリーダー; } public 注文読込() { String 一行 = ファイルリーダー.一行読込(); ・・・ 「準備してもらう」ための仕組みを用意した

  42. Yさん:「ごめん、LF改行ファイルリーダークラスがYさん:「ごめん、LF改行ファイルリーダークラスが      まだできてないんだよ」

  43. モッククラス※で動作確認 class モックファイルリーダー implements ファイルリーダー { public String 一行読込() { return "test001,東京企画,営業部,p001,3000"; } } public class 動作確認 { public static void main(String[] args) { モックファイルリーダー ファイルリーダー = new モックファイルリーダー(); A社注文リーダー A社注文リーダー = new A社注文リーダー(); A社注文リーダー.set区切文字(”、”); A社注文リーダー.setファイルリーダー(ファイルリーダー); A社注文 A社注文 = A社注文リーダー.注文読込(); System.out.println(A社注文.get注文ID()); System.out.println(A社注文.get会社名()); System.out.println(A社注文.get部署名()); System.out.println(A社注文.get製品ID()); System.out.println(A社注文.get値段()); } } ※ 見かけ上正しく動くクラス

  44. "DIする"という表現 ・・・ A社注文リーダー A社注文リーダー = new A社注文リーダー(); A社注文リーダー.set区切文字(”、”); A社注文リーダー.setファイルリーダー(ファイルリーダー); ・・・

  45. Bさん:「LF改行ファイルリーダークラスできたから、Bさん:「LF改行ファイルリーダークラスできたから、      使ってみてよ。      ファイルパスと文字コードは、DIできるよ。」

  46. public class 動作確認 { public static void main(String[] args) { LF改行ファイルリーダー ファイルリーダー = new LF改行ファイルリーダー(); ファイルリーダー.setファイルパス("test.csv"); ファイルリーダー.set文字コード("EUC_JP"); A社注文リーダー A社注文リーダー = new A社注文リーダー(); A社注文リーダー.set区切文字(”、”); A社注文リーダー.setファイルリーダー(ファイルリーダー ); A社注文 A社注文 = A社注文リーダー.注文読込(); System.out.println(A社注文.get注文ID()); System.out.println(A社注文.get会社名()); System.out.println(A社注文.get部署名()); System.out.println(A社注文.get製品ID()); System.out.println(A社注文.get値段()); } }

  47. 上司:「そろそろ結合テストだから、      ベテランのCさん、「準備する」部分の実装をお願い」 適した時期に、適した人が「準備する」部分 を作り込むことができる

  48. プログラム全体のクラス図 《create》 Xさんの担当したクラス A社注文 B社注文 《インターフェース》 注文リーダー 《インターフェース》 コンバーター 《インターフェース》 注文ライター A社注文リーダー B社注文リーダー A社注文ライター B社注文ライター A_Bコンバーター B_Aコンバーター 《インターフェース》 ファイルリーダー ファイルライター LF改行 ファイルリーダー CRLF改行 ファイルリーダー

  49. プログラム全体の「準備する」部分を集約 public class コンフフィギュレーション { public static エグゼキューター コンフィギュア() { LF改行ファイルリーダー ファイルリーダー = new LF改行ファイルリーダー(); ファイルリーダー.setファイルパス("data/A社注文.csv"); ファイルリーダー.set文字コード("EUC_JP"); A社注文リーダー 注文リーダー = new A社注文リーダー(); 注文リーダー.set区切文字(","); 注文リーダー.setファイルリーダー(ファイルリーダー); A_Bコンバーター コンバーター = new A_Bコンバーター(); ファイルライター ファイルライター = new ファイルライター(); ファイルライター.set改行文字("\r\n"); ファイルライター.set文字コード("Shift_JIS"); ファイルライター.setファイルパス("data/B社注文.txt"); B社注文ライター 注文ライター = new B社注文ライター(); 注文ライター.set区切文字("\t"); 注文ライター.setラインライター(ラインライター); エグゼキューター エグゼキューター = new エグゼキューター(); エグゼキューター.set注文リーダー(注文リーダー); エグゼキューター.setコンバーター(コンバーター); エグゼキューター.set注文ライター(注文ライター); return エグゼキューター; } }

  50. プログラムの実行 public static void main(String[] args) { エグゼキューター エグゼキューター = コンフィギュレーション.コンフィギュア(); エグゼキューター.実行(); }

More Related