「徹底攻略 Java SE 11 Silver 問題集」から学ぶオブジェクト指向設計

# 前置き

現在参画している現場でJavaの案件に携わることになりました。
しかし、エンジニア歴15年目になるにも関わらずずっと.NET周りの技術しか扱ってこなかったので、今回が初のJava案件になります。
そこでJavaの基礎知識をゼロベースで学ぶために、Java SE 11 Silver/Goldの取得を目標とした学習を始めることにしました。

学習を始めるに当たり、まずは[徹底攻略 Java SE 11 Silver 問題集](https://www.amazon.co.jp/dp/4295007625/)（いわゆる「黒本」を購入しました。

回答の解説が非常に丁寧に記載されているので、試験対策だけでなく基礎知識を学ぶのに最適な教材だと感じたのですが、自分は書籍内で「参考（試験対策と直接関係ないが、知っておくと有益な情報）」と記載されている箇所に注目しました。

「参考」の箇所でも、特に今後「オブジェクト指向」を深堀りしていくのであれば非常に重要となる記述が散見されたので、今回の記事ではそれらをまとめてみようと思います。

# P51より：不変（immutable）オブジェクト

「第2章　Javaの基本データ型と文字列操作」のStringオブジェクトに関する問題の解説からです。
データが不適切に変更されることを防ぐための「不変（immutable）オブジェクト」の実装例が記載されています。これはDDD（ドメイン駆動設計）における「Value Object（値オブジェクト）」の実装に必須となる知識です。

参考：[設計要件をギッチギチに詰めたValueObjectで低凝集クラスを爆殺する](https://qiita.com/MinoDriven/items/5e69d9bd028aa350e2c4)

# P203より:引数が多いほどメソッドは使いにくくなる

「第6章 インスタンスとメソッド」における、呼び出し元メソッドとメソッド宣言で定義している引数の数についての問題の解答からです。

* 引数が多いほどそのメソッドは使いにくくなってしまう
* たくさんの引数を受け取るメソッドを定義するのであれば、それらの引数をフィールドに持つ1つのオブジェクトを受け取るようにしたほうが、より簡潔で変更にも強くなる

といった参考情報が記載されています。

私が最近見かけた具体例ですと
[ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本](https://www.shoeisha.co.jp/book/detail/9784798150727)
のサンプルコードで引数をフィールドに持つオブジェクト「〜Command」と定義する「コマンドオブジェクト」戦略が非常にわかりやすい良例だと思います。

### 引数をフィールドに持つ「〜Command」オブジェクト例
https://github.com/nrslib/itddd/blob/master/Layered/SnsApplication/Users/Get/UserGetCommand.cs

### 「〜Command」オブジェクトを呼び出すメソッド例
https://github.com/nrslib/itddd/blob/master/Layered/WebApplication/Controllers/UserController.cs#L36

こちらのサンプルコードでは戻り値も「〜Result」オブジェクトとしてまとめていることで、簡潔で変更に強い設計になってい点も参考になると思います。

# P220より:カプセル化

「第6章 インスタンスとメソッド」における、カプセル化の概念に関する問題の解説からです。
こちらの問題は「コードが提示されていてそこにカプセル化を適用したい。以下から最適なコードを選べ」といった内容です。
よって、「カプセル化」に関する知識は試験対策としても必須な知識となるのですがオブジェクト指向においても同様の知識と思われます。
カプセル化については以下のように解説されています。

>カプセル化は、ソフトウェアを分割する際に、関係するデータとそのデータを必要する処理を1つにまとめ、無関係なものや関係性の低いものをクラスから排除することで「何のためのクラスなのか？」というクラスの目的を明確化するために行い、ほかのクラスに重複するデータや処理がない状態を目指すものです。

前述のValue Objectはまさに「カプセル化」を実現するための手法の1つです。
そして、「カプセル化」したオブジェクトを実装するためには「データ隠蔽」、Javaにおいてはオブジェクト内のフィールドはprivateで修飾（隠蔽）し、フィールドの値を使ったメソッドを公開（public）することと、といったことも記載されています。

# P244より:「継承」は使われなくなってきている

「第7章 クラスの継承、インターフェース、抽象クラス」における、クラスの継承に関する問題の解説からです。
クラスの継承はオブジェクト指向言語においては必須となる知識ですが
>最近では、継承を使うことで保守性が低下する可能の高まりが指摘されています。

と記述されています。
継承を安易にしようしてしまうとどのような事が起きてしまうかは、以下の投稿で解りやすく解説されています。

[君の継承の使い方は間違っている](https://qiita.com/tonluqclml/items/c0110098722763caa556)

あなたが保守しているシステムにも「AbstractController」とか「AbstractService」みたいな共通処理が多数実装された「神・基底クラス」が存在していたりしませんか？

実装方法が継承よりもハードルが高いかもしれませんが、継承を使いたくなったら「移譲」や「合成」を検討するのが現代のオブジェクト指向設計のベストプラクティスなのかもしれません。

[オブジェクト指向と10年戦ってわかったこと]
(https://qiita.com/tutinoco/items/6952b01e5fc38914ec4e)

# p259より：リスコフの置換原則

「第7章 クラスの継承、インターフェース、抽象クラス」における、メソッドのオーバーライドに関する問題の解説からです。
参考情報として「サブクラスはスーパークラスと置き換え可能でなければいけない」という原則、「リスコフの置換原則（LSV:Liskov Substitution Principle）」が紹介されています。
オブジェクト指向にはほかにもたくさんの原則があること、より良い設計をするためにはこれらの原則をしっかりと学習することを勧める、といった記載もあります。
これらの原則の代表例といえば「リスコフの置換原則」も含めた5つの原則、いわゆる「SOLID原則」です。

* Single Responsibility Principle：単一責任の原則
* Open/closed principle：オープン/クロースドの原則
* Liskov substitution principle：リスコフの置換原則
* Interface segregation principle：インターフェース分離の原則
* Dependency inversion principle：依存性逆転の原則

SOLID原則については、以下の投稿がコード例も添えて解りやすく解説されています。

[SOLID原則について簡単に書く](https://qiita.com/yui_mop/items/93fef037a787318e7067)

# P283より:デザインパターンとStrategyパターン

「第8章　関数型インターフェース、ラムダ式」のおけるラムダ式の基本的な宣言方法に関する問題の解説からです。
本設問のコード自体が、Strategyパターンをラムダ式を使って実現したものとなっており、そこからGoFのデザインパターンの紹介とStrategyパターンの解説が記載されています。

Javaとデザインパターンと言えば、もう15年前の出版物となってしまいますが
[増補改訂版 Java言語で学ぶデザインパターン入門](https://www.amazon.co.jp/dp/4797327030/)
を思い出しました。
当時、Javaは扱っていませんでしたがデザインパターンの実装例がサンプルコードともに掲載されており、非常に勉強になりました。
Amazonのレビュー上ではここ1〜2年の間でも高評価のレビューが投稿されているので、今も変わらず名著と評価されているようです。

# まとめ

以上、「徹底攻略 Java SE 11 Silver 問題集」の「参考」情報からより深くオブジェクト指向設計を学ぶための補足となるような形でまとめてみました。
本問題集を読んだJavaおよびプログラミング初心者（あるいはベテランの方も？）の方が、本記事にたまたまたどり着いてオブジェクト指向をより深く学んでいくきっかけに繋がったら幸いです。