はじめに
学んだことについて自身で記事を書いた方が理解が曖昧なところを炙り出せるという助言をいただきました。
そして先日オブジェクト指向とドメイン駆動設計を学ぶ機会がありましたので今回当記事を作成するに至りました。
本記事を読み、自分も記事を投稿し、学びを深めよう!と思われる方がいらっしゃいましたら大変嬉しいです。
オブジェクト指向とは?
オブジェクト指向とは各オブジェクトがそれぞれの役割分担された役割をもって動き、それぞれがそれぞれの役割を果たしていき、またそれぞれのオブジェクト同士が協調していくことで全体として一つの仕組みが動作するという考え方。
世の中もそうですよね。様々な人が役割分担をしていくことで一つの仕事を成し遂げていけます。
重要な3要素
オブジェクト指向には以下の重要な3つの要素があります。
1. カプセル化
データのまとまりとそれに付随する手続きを全てまとめ情報隠蔽し、外部からは手続きの呼び出しのみによって操作できるようにすること。
これにより外部から想定しない要素を利用されることを防ぎます。また外部の人は内部構造を詳しく知らなくても行いたい手続きを行えるようになります。
少し分かりにくいので具体例を交えて説明します。
カプセル化されていない状態を考えましょう。もしカプセル化がされていないと、例えば口座クラスに関して、特定の口座からお金を引き出すメソッドがどこからでも呼べる場合勝手に口座からお金が引き出されてしまいます。これは大問題です。また誤まってシステムの中枢部にアクセスしてしまい壊してしまうということも起きえます。
これらのようなことを起きないようにするため、必要最低限のものだけを公開し外部で使えるようにし、あとのものは隠蔽し特定の操作によってのみアクセスし使えるようにすることがカプセル化なのです。
実装方法は以下のようになります。
//外部に公開されないフィールドの定義
private string name;
private int age;
//外部に公開されるメソッドの定義
public void run(){
};
上記のようにアクセス修飾子(private,publicなど)を設定することで意図しないアクセスを防ぐことができます。
2. 継承
クラスに上下関係を持たせてあるクラスが別のクラスの性質を受け継ぐようにすること。
受け継いだクラスの重複部分をなくし記述性、保守性を向上させることを目的としている。
実装方法は以下のようになります。
//車クラス
class Car
{
public string name;
//走るメソッド
public void run();
}
//消防車クラス
class FireEngine : Car
{
//放水するメソッド
public void spraywater();
}
//スポーツカークラス
class : SportsCar : Car
{
//屋根を開けるメソッド
public void open();
}
このようにすることで車クラスを継承した消防車クラスとスポーツカークラスは車クラスが持っていた特徴(フィールド、メソッド)をそのまま受け継ぐことができます。
こうすることによりrunメソッドに不具合があった際はもとのrunメソッドを直すだけでよいことになります。
もし車クラスというものがなかった場合、runメソッドを消防車クラスとスポーツカークラスにコピーコードとして用意することになり修正にも手間がかかります。
3. ポリモーフィズム
同一メッセージ(オブジェクト間での情報のやりとり)に対して受信したオブジェクトごとに異なる振る舞いをできるようにすること。
よく説明された図を見かけたことがあると思いますが「鳴け」という一つの命令(メソッド)でいぬとねこが別の鳴き声で答えてくれるというものですね。
もしポリモーフィズムがないとそれぞれいぬに「ワン!」鳴くメソッド、ねこに「にゃー」と鳴くメソッドが必要になってしまいます。
メリット
- プログラムの内部構造が明確化され品質が向上する。
- コードの修正が容易になるため保守性が向上する。
デメリット
ただしオブジェクト指向にもデメリットはあります。
- 正しく理解していないまま使用するとさまざまなクラスへの依存が高まり保守性が落ちてしまう
- is-Aの関係になっていないものに対して単純にコードの再利用や機能の追加のためだけに継承を用いると、クラス間の依存関係が複雑化してしまう。
※is-Aの関係 「は~の一種」が成り立つ関係
以上が私がオブジェクト指向について学んだことです。ここからはオブジェクト指向を実現する手法の一つであるドメイン駆動設計についての学びをまとめます。
ドメイン駆動設計とは
ドメインに焦点をあてドメインモデルを形成しそれをコードに落とし込もうとする設計手法のこと。
そもそもドメインとは
専門領域のこと。例えば銀行であったり病院などでの仕事のことです。これらの場所で働く人たちが持っている専門の知識をドメイン知識と言います。
また、ドメインモデルは対象のドメインから価値のある必要な知識を抽出したものです。銀行のシステムでいうとお金の取引方法や顧客の情報などが「必要な知識」に当たります。逆に銀行のシステムに顧客の名前の由来などは「不必要な知識」に当たります、システム自体にはいりませんもんね。
ドメイン駆動設計について重要な要素が4つあります。
ユビキタス言語
ドメインモデルに基づく言語。
レビューやコード、どんな形態のコミュニケーションでもユビキタス言語を決めておくことで設計の全ての部分が結びつき、設計チームが効率良く作業をするための前提が生まれる。
例えば「アジャイル開発」と技術者が会議で発言したとします。我々はアジャイル開発がどういうものか頭に思い浮かぶと思いますが営業の人たちには思い浮かばない可能性が高いと思います。
逆に営業の人が「リードナーチャリングを~」(調べた)といった時、それがなんなのか思い浮かばない...ですよね?
このようなことが会議で起こりいちいち説明をしていると開発に支障がでます。
あらかじめ双方の立場の人たちが分かるような言葉を双方の立場の人たちが話し合い決めておくことで開発をスムーズに進めることができるようになるのです。
エンティティとバリューオブジェクト
エンティティ
一意性が保証されたオブジェクトのこと。可変性をもち生成されてから属性が変わることがある。
バリューオブジェクト
エンティティと異なり一意性を保証する必要がなく、ドメインの一つの側面を表現するための不変なオブジェクト。一意性を保証する必要がないため好きなだけコピーが可能であり、また好きなときに破棄できる。
通常の状況を考えるとマイナンバーカードはバリューオブジェクトですが、マイナンバー自体はエンティティとなります。どういう違いがあるのでしょう?
マイナンバーカードは皆さん持たれていて「マイナンバーカード」と言っても一意には特定できません。しかし、「マイナンバー」というものは各個人によって異なりマイナンバーだけで一意に特定することができます。
上記の考え方で考えるとお金はバリューオブジェクト!社員はエンティティだ!と考えてしまいがちですがそういうわけにはいけないんですよね...
実は状況によるんです。
5000円札は5000円の価値であるものでしかないけどコレクターからすると5000円という価値ではなく5000円札の種類、樋口一葉の5000円札、聖徳太子の5000円札、さらに記番号が〜いうようにでというように一意に識別できます。このようにとらえ方によってお金もエンティティになるのです。
ちなみに余談ですが来年の5000円札は津田梅子という方になるようです。
集約(アグリゲート)
関連するオブジェクトの集まりのことでデータの変更について一括して扱うことができる。エンティティのルート(階層構造の根本)を持っており、外部からアクセスできる唯一のオブジェクト。
例えば、オンラインストアの注文アグリゲートを考えてみましょう。注文アグリゲートには注文自体がルートエンティティとして含まれ、注文に関連する商品や顧客情報などが他のエンティティやバリューオブジェクトとして集約されます。注文アグリゲート全体の一貫性や変更は、ルートエンティティである注文によって管理されます。
おわりに
読んでいただきありがとうございました。コメントやご指摘等ございましたらお願いします。