1.1K Views
October 25, 24
スライド概要
2024/10/25 社内勉強会の資料
より良い設計を目指すための小話、Adapter、Factory Method、Singletonをテーマにしている。
組込みソフトウェアエンジニア。 技術バックボーンはC言語・ベアメタル。 CQ EVカートのオーナーで、ハード・ソフトウェアの改造を通じて自身のスキルアップを日々考え中・・・。 LAPRASポートフォリオ: https://lapras.com/public/k-abe GitHub: http://github.com/grace2riku Qiita: https://qiita.com/juraruming Zenn: https://zenn.dev/k_abe よろしくね。
【連続講座1】デザインパターンを学 び、ソフトウェア設計に生かそう ・Factory Method・Singleton パーソルクロステクノロジー株式会社 エンジニアリング事業管掌 設計統括本部 第2電子・制御設計本部 第1設計部 4G 阿部耕二 Adapter
目次 自己紹介 開発環境構築 設計、してますか? 良い設計とはどういう設計か? デザインパターンの学び方のススメ Adapter Factory Method Singleton 参考資料 2
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 自己紹介 名前: 阿部 耕二(あべ こうじ) 所属: パーソルクロステクノロジー株式会社 エンジニアリング事業管掌 設計統括本部 第2電子・制御設計本部 第1設計部 4G 医療機器の組込みソフトウェア開発。C言語。 趣味: 宇宙開発(リーマンサットプロジェクト広報メンバー) LAPRAS ポートフォリオ : https://lapras.com/public/k-abe Twitter: @juraruming 3
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 開発環境構築 サンプルコードのコンパイル、実行にjava(JDK)のインストールが 必要です。 下記のページなどを参照し、ご自分のPCのOSに合わせてインストー ルしてください。 【2024年版】Java JDKのインストール方法(Windows & Mac対応) 4
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう つぎのコマンド実行でバージョンが表示されていればOKです。 私はつぎのバージョンで確認しました。 $ javac -version javac 17.0.8 5
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう サンプルプログラムのビルド方法 サンプルプログラムのディレクトリ(Main.javaがあるディレクトリ) に移動しつぎのコマンドでビルドする。 $ javac Main.java プログラムの実行はつぎのコマンドで行う。 $ java Main 6
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 講座のGitHubリポジトリ https://github.com/grace2riku/design_pattern_lesson 今回の講座のディレクトリ https://github.com/grace2riku/design_pattern_lesson/tree/main/le sson_1 参考資料1 ソースコードのダウンロード先 Java 言語で学ぶデザインパターン入門 第 3 版 7
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 設計、してますか? 設計してますか? 8
【連続講座1】デザインパターンを学び、ソフトウェ こんなことになってませんか? おばあちゃんのプログラミン グ教室(ばあプロ)As A Service @Pythonist19 より引 用 https://x.com/Pythonist19/sta tus/1845794841269055543 9
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 設計の重要性 要素技術にフォーカスしがち、注力しがち → 再利用しにくい、変更しにくいソフトウェアのできあがり 他社との違い・自社の強みを活かしていないソフトウェアが誕生 ビジネス競争力の低下 → 技術的負債に!!! 10
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 設計の難しさ お手本がない。 対象製品、装置で個別の事情がある。 製品の特性、開発期間、製品寿命、etc Web システムと組込みソフトウェア 自動車と医療機器では設計思想も違ってきそう。 自動車:変化が早い、開発期間短い、大量生産 医療機器:開発期間長い印象、少量生産 ソフトウェアは柔軟で、自由度が高すぎる。 11
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 対象システム、装置に応じた設計手法を学び、身につける そしてチームメンバーと共通認識を持ちたい。 デザインパターン 設計の古典、教科書ともいえる。 プログラミング言語の中に取り込まれて、見えない。 → 学ぶことは意味があると考える。 → 開発時のコミュニケーションに活用する。 ここは「xxx」パターンを適用してみようか? 12
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 良い設計とはどういう設計か? 良い設計のために個人的に大事だと思うキーワード 1. 凝集度 2. 結合度 3. 関心の分離 13
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 1. 凝集度 関心ごとの集まり 凝集度が高い方(関心ごとが一箇所に集まっている)が良い設計と 言われる 1 つの目的・責務になっていることが望ましい 例)料理を作る場面 キッチン周りには料理に必要な設備が配置される(水道、冷蔵庫、コ ンロ、食器棚、その他)。 →必要なものが凝集している状態 キッチン周りに洗濯機はいらない。料理をつくるという関心ごとに洗 濯機は不要。 14
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 2. 結合度 他のモジュールとの関連の度合い 結合度が低い方(他のモジュールとの関連が少ない方)が良い設計 と言われる あるファイルのグローバル変数が他の複数のファイルから参照され ている状況は結合度が低い。 15
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 関心の分離 関心ごとを分離し、境界を設ける 関心の分離が表現されている例としてOSI参照モデル・TCP/IPに注 目する “ 画像引用元 OSI 参照モデルとは? TCP/IP との違いを図解で解説 “ 3. 16
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 役割ごとに階層が分かれている 下の層がハードウェアに近い 17
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 18
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 上の階層ほど抽象的。目的・知識・Why。 下の階層ほど具体的。目的を達成する手段・How。 19
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう デザインパターンの学び方のススメ デザインパターンがどんな課題を解決できて、どのような構成なの かイメージを捉える 参考資料1の章題はデザインパターンを短く端的に表現してい る。 参考資料3では各デザインパターンを短く、わかりやすく解説し てくれている。 20
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう クラス図とコードの写経をセットで行う コードだけ見ていても各クラスの全体の関係性がわかりずらい。 クラス図だけを見ていても抽象的で本当に動くのか疑問がわく。 設計図(抽象) ⇔ コード(具体的)の世界を行ったり来たり することで整理できたり、気づきが得られることがあると思う。 今回のサンプルコードはJava。デザインパターンの考え方・実装 は特定のプログラミング言語に限定されないと思うので自分が得 意な言語で実装してみると理解が深まると思う。 参考資料2ではC#、 C++、 Go、 Java、 PHP、 Python、 Ruby、 Rust 、 Swift 、 TypeScript で実装例を提示してくれている。 21
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう デザインパターンに登場するクラスの相互関係に注目する 複数のクラスが関係してパターンを構成している。各クラスの役 割、関係性に注目する。 デザインパターンがどのように振る舞うか?に加えて、デザインパタ ーンはどのように使われるか?の視点も大事だと思う。 22
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう Adapter 参考資料1 章題 【一皮かぶせて再利用】 すでに提供されているものがそのまま使えないときに、必要な形に 変換してから利用する パソコンのACアダプター(直流12Vで動く製品とする) 提供されているもの -> 交流100V AC アダプタが変換するもの -> 交流を直流に変換。交流 100V をパソ コンが動作する12Vに変換する 23
【連続講座1】デザインパターンを学び、ソフトウェ 例)Apple ACアダプタ Apple の AC アダプタの構造 24
【連続講座1】デザインパターンを学び、ソフトウェ アダプタのプラグ部分は取り 外し可能で海外でも使えるよ うに考慮されている(設計し た)と予想できる。 調べてみたらApple ワールド トラベルアダプタキットなる 製品があり、7種類のプラグ形 状があることがわかった。 プラグ部分を容易に変更でき る構造になっている。 このように容易に変更できる 構造をソフトウェアにも持ち 込みたい!!! 25
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう パターンのサンプルプログラム例 テーマ:既にある加算に下限・上限の制限を追加する。 例えば、下限O、上限100のときに加算の計算結果が上限値を超えた ら上限値の100にする。 加算の計算結果が下限値を下回ったら下限値の0に固定する。 表 電源の比喩とサンプルプログラムの対応関係 \ 電源の比喩 サンプルプログラム 提供されているもの 交流100ボルト Calcクラス 変換装置 アダプター LimitCalcクラス 必要なもの 直流12ボルト Limiterクラス Adapter 26
【連続講座1】デザインパターンを学び、ソフトウェ サンプルプログラムのクラス図 サンプルプログラムのディレク トリ https://github.com/grace2riku /design_pattern_lesson/tree/ main/lesson_1/adapter/LimitC alc 27
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう サンプルプログラムのビルド方法 サンプルプログラムのディレクトリ(Main.javaがあるディレクトリ) に移動しつぎのコマンドでビルドする。 $ javac Main.java プログラムの実行はつぎのコマンドで行う。 $ java Main 28
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう Adapter サンプルプログラムの実行結果 $ java Main /***** Calc *****/ ret_val(0 + 101) = 101 ret_val(0 + (-1)) = -1 /***** LimitCalc *****/ limit min value = 0/limit max value = 100 ret_val(0 + 50) = 50 ret_val(0 + 100) = 100 ret_val(0 + 101) = 100 ret_val(0 + 0) = 0 ret_val(0 + (-1)) = 0 はリミットなしの加算。LimitCalcはリミットありの加算 LimintCalc の下限は 0 、上限は 100 に設定 Calc 29
【連続講座1】デザインパターンを学び、ソフトウェ パターンの登場人物を 抽象的に書く Adapter 30
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう パターンの使いところ 既にあるクラスを変更せずに再利用できる 変動部(Target)をバリエーション化すれば素早く多くのバリエー ションに対応できる(競合他社との差別化) Adapter 31
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう Factory Method 参考資料1 章題 【インスタンス作成をサブクラスにまかせる】 インスタンス作成するクラスを用意する(あちこちでインスタン作 成せずに、インスタンス作成役に任せる)。 32
【連続講座1】デザインパターンを学び、ソフトウェ サンプルプログラムのクラス図 サンプルプログラムのディレク トリ https://github.com/grace2riku /design_pattern_lesson/tree/ main/lesson_1/Factory_Meth od 33
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう サンプルプログラムのビルド方法 サンプルプログラムのディレクトリ(Main.javaがあるディレクトリ) に移動しつぎのコマンドでビルドする。 $ javac Main.java プログラムの実行はつぎのコマンドで行う。 $ java Main 34
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう Adapter サンプルプログラムの実行結果 $ java Main /***** IDCardのFactory *****/ Hiroshi Yukiのカードを作ります。 IDCard [owner=Hiroshi Yuki]を登録しました。 Tomuraのカードを作ります。 IDCard [owner=Tomura]を登録しました。 Hanako Satoのカードを作ります。 IDCard [owner=Hanako Sato]を登録しました。 IDCard [owner=Hiroshi Yuki]を使います。 IDCard [owner=Tomura]を使います。 IDCard [owner=Hanako Sato]を使います。 /***** BussinesCardのFactory *****/ Koji Abeの名刺を作ります。 BusinessCard [owner=Koji Abe]を登録しました。 Riku Abeの名刺を作ります。 BusinessCard [owner=Riku Abe]を登録しました。 BusinessCard [owner=Koji Abe]を使います。 BusinessCard [owner=Riku Abe]を使います。 35
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう サンプルプログラムの実行結果 IDCard の Factory は参考資料 1 のサンプルコード BussinesCard の Factory は今回追加した名刺の Factory と商品の名刺 フレームワークのパッケージ内は変更せず、具体的な工場・商品の 追加で新しい種類のインスタンス作成ができた Adapter 36
【連続講座1】デザインパターンを学び、ソフトウェ パターンの登 場人物を抽象的に書く Factory_Method 37
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう パターンの使いところ インスタンス生成を専門にするクラスを用意することでコードを整 理できる 工場に使えばインスタンスを作成できる。 Factory_Method 38
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう static Factory Method 参考資料1より引用 インスタンス生成のためのクラスメソッド(クラスをインスタンス 化しなくても呼び出し可能なメソッド) GoF の Factory Method パターン違うが、インスタンス生成でよく使 われる手法。 (個人的に開発シーンでFactoryと呼ぶときはこちらを指すことが 多いと思っている) “ “ 39
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう static Factory Method のAPIのstatic Factory Methodとして参考資料1で紹介されてい るものは以下のとおり java.security.SecureRandom の getInstance メソッド java.util.List の of メソッド java.util.Arrays の asList メソッド java.lang.String の valueOf メソッド java.time.Instant の now メソッド java 40
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう Singleton 参考資料1 章題 【たった1つのインスタンス】 システムにインスタンスが1つしかないことを保証する。 プログラマがインスタンスを1つしかつくらないように気を付ける のではなく、インスタンスが1つしかつくれないような仕組みにす る。 41
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう システムの中で複数あると困りそうなもの プリンタのジョブ管理 デバイスドライバ Factory Method の Factory 42
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう パターンのサンプルプログラム例 テーマ:システムに1つのものを対象にする。今回はプリンタのジョブ Singleton 43
【連続講座1】デザインパターンを学び、ソフトウェ サンプルプログラムのクラス図 サンプルプログラムのディレク トリ https://github.com/grace2riku /design_pattern_lesson/tree/ main/lesson_1/Singleton/Prin tJob 44
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう サンプルプログラムのビルド方法 サンプルプログラムのディレクトリ(Main.javaがあるディレクトリ) に移動しつぎのコマンドでビルドする。 $ javac Main.java プログラムの実行はつぎのコマンドで行う。 $ java Main 45
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう Singleton サンプルプログラムの実行結果 $ java Main Start. インスタンスを生成しました。 printjob1とprintjob2は同じインスタンスです。 End. 「インスタンスを生成しました。」のメッセージが1つなので、イン スタンスは1つのみ生成されている。 getInstance メソッドで取得したインスタンスは同じことを確認でき た 46
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう パターンの使いところ インスタンスが1つであることを保証したい時 組込みソフトウェアのデバイスドライバなど。 データベースのアクセス Factory Method の Factory (インスタンスを作成する工場はひと つでよいことが多いと思う) Singleton 47
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう おまけ:Singletonの実装を変更してみる サンプルコード: https://github.com/grace2riku/design_pattern_lesson/tree/main/less on_1/Singleton/PrintJob_2_1 48
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう ディレクトリ名:PrintJob_2_1 Singleton のインスタンス生成の実装を下記に変更(インスタンスが生 成済みかnullチェックするようにした) public class PrintJob { private static PrintJob printJob = null; private PrintJob() { System.out.println("インスタンスを生成しました。"); } public static PrintJob getInstance() { if (printJob == null) { printJob = new PrintJob(); } return printJob; } } 49
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう サンプルコード:PrintJob_2_1を動かすとSingletonの動きが確認でき ます。 ・・・確認できますが、このコードには 考慮していないこと 呼び出し方にはよっては意図しない動作をする可能性 があります。 それは何でしょう? つぎのページを見ずに考えてみてくださいね 50
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 前ページの解答 マルチスレッド環境でgetInstanceを実行すると異なるインスタンス を取得してしまう(Singletonでなくなる) 51
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう をマルチスレッドで実行するように変更したコード ( )で動きを確かめてみる サンプルコード: PrintJob_2_1 PrintJob_2_2 https://github.com/grace2riku/design_pattern_lesson/tree/main/less on_1/Singleton/PrintJob_2_2 52
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう PrintJob_2_2 をコンパイル・実行するとつぎの結果になる。 Start End インスタンスを生成しました。 インスタンスを生成しました。 インスタンスを生成しました。 PrintJob B: obj = PrintJob@1151bbe3 PrintJob C: obj = PrintJob@7b63961c PrintJob A: obj = PrintJob@4230a45b つインスタンスをつくっており、異なるインスタンスになってい る。 ※PC環境によっては結果が異なるかもしれません。私のPCだと毎 回異なるインスタンスになりました。 3 53
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 何故、Singletonでなくなったのでしょうか? 54
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう Q. A. 何故、Singletonでなくなったのでしょうか? このメソッドの条件判断がマルチスレッドで実行されるため public static PrintJob getInstance() { if (printJob == null) { printJob = new PrintJob(); } return printJob; } 55
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう のコードでSingletonに対応する方法 インスタンス作成部分をマルチスレッド環境から呼び出されても唯一 のインスタンスを返すようにする。 参考資料1に書かれていた手法を紹介する。 コード PrintJob_2_2 https://github.com/grace2riku/design_pattern_lesson/tree/main/less on_1/Singleton/PrintJob_2_3 56
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう synchronized を付加する public static synchronized PrintJob getInstance() { if (printJob == null) { printJob = new PrintJob(); } return printJob; } 57
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう PrintJob_2_3 (synchronized)の実行結果 $ java Main Start End インスタンスを生成しました。 PrintJob B: obj = PrintJob@386514c2 PrintJob A: obj = PrintJob@386514c2 PrintJob C: obj = PrintJob@386514c2 インスタンスが1個だけ作成されており、Singleton対応できている ことが確認できた。 PrintJob_2_1 のコードが基本形だと思う。 PrintJob_2_1 のコードをマルチスレッド環境で実行しても Singleton 対応できている。 58
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう このことから学べるポイント どう使われるか?、どう使われる可能性があるか?、を考慮して実装 者に任せるのではなく設計者が実装者に伝えるようにする。 スレッドセーフではない実装のまま進める場合は、ドキュメントに スレッドセーフではない旨を書いておいた方が良さそう。 59
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう 参考資料 言語で学ぶデザインパターン入門 第3版 2. 直撃!デザインパターン 3. ぼくにもわかるデザインパターン 第 2 章 GoF パターン大カタログ ~パターンがみるみる頭にしみこむ~ 1. Java 60
【連続講座1】デザインパターンを学び、ソフトウェア設計に生かそう ご清聴ありがとうございました 61