オブジェクト指向設計

C#でカプセル化を使ったオブジェクト指向設計の実装方法を解説!!

C#でオブジェクト指向プログラミングをする上で大切な3つのこと「カプセル化」「インタフェース」「継承」がありますが,今回はその中の「カプセル化」について解説します。

オブジェクト指向設計のカプセル化ってどういう意味?

カプセル化とはどんな意味かといいますと,値をクラスで包むことです。
例えばこんな感じです。

ポイントは一番上の「private readonly decimal _value; 」の部分ですね。
このMoneyクラスは「_value」というdecimalの値をカプセル化していることになります。

「_value」はprivateに設定されているため,他のクラスから直接「_value」の値にアクセスことはできませんよね?だからこの「_value」を書き換えることも,読み込むことも,Moneyクラスにお願いしないと変更することができない。こういう状態を「_value」はMoneyクラスにカプセル化されている状態といいます。

カプセル化されていると何がいいのか?

このMoneyクラスのポイントは「_value」がMoneyクラス経由でしか扱えないことです。
Moneyクラスの「_value」はお金の金額を示します。

公開されているプロパティの「Value」はそのままの金額「_value」の値が返却されますが,「TaxValue」を呼び出すと,消費税込みの値「1.08倍」された値が取得できます。

例えばあなたが,お金を扱うシステムの開発を行っている場合,消費税を加えた値というのは,いたるところで扱うことになります。

このMoneyクラスを作らずに,単にプログラム上に「decimal」を宣言にしてコーディングしていた場合,消費税込みの値として扱いたくなった場合はどうすればよいでしょうか?
画面プログラムなどに直接decimal変数を宣言する場合は,次のようなコーディングになりがちです。

取得したGetAmount()のdecimal値を直接取得すると,その値に対して消費税を足そうとすると,直接1.08倍をするコーディングになる可能性があります。

こうなってしまうと,プログラムのあらゆるところで,消費税の計算ロジックが書き込まれ,消費税か変化したときに,修正箇所が膨大となります。

新人
新人
decimalに1.08倍する共通関数を作っておけばいいんじゃないですか?

共通関数を作ればいいのではないか?と思われる方もいるかもしれません。その場合,あらゆるところを修正する必要はなくなるかも知れませんが,それだけでは問題は解決しません。

仮に「TaxFunc」という共通関数を作ったとしましょう。

アンダーソン
アンダーソン
すべての金額を使用している箇所で「TaxFunc」がちゃんと使われていると確認できるでしょうか?

確かに「TaxFunc」のような関数を作れば1.08倍というマジックナンバーは共通化できます。しかし,「金額」という値を扱うときに,全プログラマーが共通意識を持って,どの程度その「TaxFunc」を使えているか?そして,金額を扱っている場所が何箇所あって,すべてが「TaxFunc」になっていると確認できるか?という問題があります。

「Money」クラスのよいところはずばりこの一言に尽きます

値とロジックが1つになっている

オブジェクト指向設計がうまくできない人はこれが理解できていません。
オブジェクト指向設計の大切な考え方「カプセル化」は「クラス」というものが存在している理由そのものです。「値」と「ロジック」を1つにまとめておく。これが,可読性の高いプログラムを作る秘訣です。

今回の場合はdecimal型の「_value」という「値」と「TaxValue」という1.08倍するロジックがいったいとなった「Money」というクラスを作成しました。decimal型だけでは到底表現できなかったことをMoneyクラスは実現しています。

カプセル化するとどんなメリットがあるのか?

これまで解説してきたようにカプセル化することで,次のようなメリットが得られます。

  1. コードが読みやすくなる
  2. 保守性が高まる
  3. ロジックが散らばらない(ロジックの住処になる)
  4. 値とロジックをセット考えることができる

カプセル化されていないと何がいけないのか?

一方カプセル化しなかったら何が悪いのか?decimal型を単体で持つことになるので,値とロジックを別々に持つことになります。値が生成されたときに,その値自体にロジックがあれば,プログラマーはどこも探すことなく,値に付随しているロジックを使用します。
C#でいえば「.ドット」をつけたときに出てくる「インテリセンス」の中から,関数を選ぶだけでよくなります。

だから,例えばデータベースから「金額」を取得する場合は「decimal」型などの数値クラスで取得するのではなく「Money」クラスなどのカプセル化したクラスで返却しましょう。そうすれば,「金額」を扱っている場所が何箇所あるのか?税込み計算はどのようにしているのか?ということも「右クリック.すべての参照を検索」とすれば調べることができます。

まとめ

値を扱うときはintなどの数値型で扱うのではなく「Money」クラスのようなカプセル化されたクラスを多用する。

カプセル化のポイントは「値」と「ロジック」を1つのクラスで扱う。

オブジェクト指向

C#プログラマーのための正しい3層構造が分かる「C#アーキテクチャー解説動画」をここで公開しています。よかったら見てみてください。

 

 

参考図書

ドメイン駆動開発

エリック・エヴァンスのドメイン駆動設計

実践ドメイン駆動設計

ドメイン駆動

現場で役立つシステム設計の原則

エンタープライズアプリケーションアーキテクチャパターン

デザインパターン

オブジェクト指向における再利用のためのデザインパターン

オブジェクト指向のこころ

Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本

オブジェクト指向

ジャイルソフトウェア開発の奥義 第2版 オブジェクト指向開発の神髄と匠の技
  すばらしい本です。オブジェクト指向が詰まっています。

オブジェクト脳のつくり方―Java・UML・EJBをマスターするための究極の基礎講座
  サンプルコードはjavaですが,最初にオブジェクト指向に目覚めるのに最適な本です。

Head Firstオブジェクト指向分析設計 ―頭とからだで覚えるオブジェクト指向の基本
  マンガみたいな感じで読めて,オブジェクト指向について学べます。  

Clean Code アジャイルソフトウェア達人の技

Clean Architecture 達人に学ぶソフトウェアの構造と設計

Adaptive Code ~ C#実践開発手法

.NETのエンタープライズアプリケーションアーキテクチャ

実装パターン
  廃盤のため異常に高くなりすぎなので,様子を見た方がいい気がします。一万円のボリュームがあるかどうかは微妙です。

オブジェクト指向でなぜつくるのか

レガシーコード改善ガイド

リファクタリング 既存のコードを安全に改善する

C#でオブジェクト指向をする方法

オブジェクト指向の原則1:単一責務の原則