[戻る]

Java読書会BOF「Practical Design Patterns for Java Developers」を読む会 第3回

開催概要

場所

てくのかわさき 談話室

出席者(敬称略)

高橋(智)、根本、高橋(徹)

  • 本日は、p.63「第2部 Implementing Standard Design Patterns Using Java Programmingから

Part 2: Implementing Design Patterns Using Java Programming

第3章 生成に関する設計パターン

ファクトリメソッドパターンを使用した入力に基づいたオブジェクトの作成

  • Executors ユーティリティクラスの newFixedThreadPoolメソッドとは?

    • 引数で指定したスレッド数とプールとして使用する Executorを生成するメソッド

  • 図3.2 UML図で VehicleFactoryクラスのproduceメソッドが戻り値型を書いていないがいいのか?

    • UML図では、メソッド名以外の可視性、引数、戻り値は省略可能

  • 例3.5 record型を使った実装

    • record型の宣言で型名の後ろに括弧内に列挙した型・変数がフィールドとして生成

    • record型はイミュータブル、hashcode, equals, toString, フィールドのgetterメソッドが自動で生成。getterメソッド名はフィールド名と同じ。

抽象ファクトリパターンを使用してさまざまなファミリからオブジェクトを作成する

ビルダーパターンを使用した複雑なオブジェクトのインスタンス化

  • 機械翻訳では、文章中の クラス名.メソッド名の ピリオドが文章の終端のピリオドとして翻訳され、文章がかなり怪しいものになってしまう。

  • 例3.10のコード中の slowVehicleが機械翻訳でthrowVehicleに書き換えられている!

  • ビルダーパターンの実装として2つの方法が記載されている

    • slowVehicleの生成では、ビルダーのロジックをメソッド内にまとめている

    • fastVehicleの生成では、メソッドチェーンで属性を指定する(よく見るビルダーパターンの実装)

  • p.78の Conclusionの2段落目、"to use the JVM's heap or stack - more specifically, to create a statically or dynamically..."が意味するところが不明

    • 著者がrecord型がスタックに置かれると勘違いしている可能性あり

プロトタイプパターンを使用したオブジェクトのクローン作成

  • 例3.13のコードは、github上のサンプルコードに対して2行不足しているので、次の実行結果の表示と整合していない。

    • equalsがfalseになるのは、Vehicleクラスの実装でequalsがオーバーライドされていないため、Object型のequalsが実行されるため

  • 宿題)record型をcloneできるか? cloneした場合、equalsはtrueになるかfalseか?

  • Javaでのcloneの作法を復習する必要ありそう

  • 例3.13 で、cloneをするには、VehicleクラスでCloneableの実装に加えて、publicなcloneを実装する必要あるが、サンプルコードではprotectedになっている。 サンプルはmainも含めて全て同じパッケージにつっこんでいるのでこれでも動作するが、本来は違う。

  • 例3.16で、cloneは抽象クラスVehicleに実装されており、それはObject型のcloneを呼んでいる。この場合、StringフィールドがシャロウコピーされるがStringはイミュータブルなので問題なし

シングルトンパターンでインスタンスを1つだけ確保する

  • 誤植 図3.6 OnlyVehicleクラスの中のgetInstanceの戻り値型が OnlineVehicle -> OnlyVehicle

  • 例3.17のコードは、シングルトンで取得したEngineインスタンスをequalsで比較しているが、同じインスタンスが返ってくるので、==で比較すれば良いのでは?

    • .formatted(engine, vehicle.getEngine() == engine) でよくないか?

  • 例3.20のコードは、上3行が、OnlyEngineEnum.javaの実装で、その後のコード断片は、OnlyVehicle.javaの中の一部分でコンストラクタの実装。

  • 宿題)マルチスレッド下でも今ならば、普通にsynchronizedまたはロックオブジェクトでブロックしてもいいのではないか?

    • 性能差があるのか?

  • p.85 結論で、単一責任の範囲がどこか不明確なので意図が読みづらい。オブジェクトの生成と、オブジェクトの振る舞いは責務が別とみなすと文の意図は通るが、そこまで責務を分けるべきということか?

オブジェクトプールパターンでパフォーマンスを改善する

遅延初期化パターンを使用してオンデマンドでオブジェクトを開始する

  • p.90 下5行目 -> は何を指しているのか?

  • 【誤植】図3.8 VechicleProvider型のgetVehicleByTypeメソッドの戻り値型がtypeになっているが、Vehicle型の誤植

  • 【誤植】例3.25 mainメソッドの最終行、car1.equals(car2)は、car1 == car2 の誤り

  • LazyVehicleクラスの意義がよく分からない

依存性注入パターンによるクラスの依存関係の削減

  • 宿題)JavaのServiceLoaderを使った振る舞いを理解しよう

    • 参考URL

      • https://pedrorijo.com/blog/java-service-loader/

      • META-INF/services/ の下に置くファイルは、インタフェースのFQCNで、ファイルの中身は実装クラスのFQCN

      • ファイルには複数の実装クラスのFQCNを行ごとに記述可能

      • loadの戻り値(ServiceLoader)は Iterableなので、記述した実装クラスの数だけイテレートできる

    • ServiceLoaderは、JPMS(Java Platform Module System)では、META-INF/servicesではなく、module-info.javaに記述する

まとめ

Q1. 生成と振る舞いを分離し単一責任を促進 Q2. オブジェクトプール、遅延初期化 Q4. プロトタイプパターン、ビルダーパターンも? Q5. アブストラクトファクトリーパターン、ビルダーパターン、プロトタイプパターン Q6. Yes。オブジェクトプール(一度作ったものの使い回し)、遅延初期化(使わないものは生成しない) Q7. アブストラクトファクトリパターン

本日は、p.100 まで読み終わりました。 次回は、p.101 第4章 構造に関するデザインパターン

[戻る]