目次
処理をカプセル(小箱)に分ける。そしてカプセルを「見せる」OR「隠す」
こんにちは。技術チームの岩谷です。本連載ではオブジェクト指向プログラミング(OOP)をおさらいする連載を書かせていただいています。今回は第四回として「カプセル化」について説明します。まず、いささか冗長ですが「カプセル」という単語そのものの意味を振り返らせてください。以下はウィキペディアからの引用です。
カプセル(Capsule、ドイツ語:Kapsel)とは、「小箱」を意味するラテン語の capsula に由来し、何かをつめておくための容器のことを表す。一般には大きさを問わず筒状の物の両端を球状にして密閉した形の物を指す。
引用元:ウィキペディア
小箱…。なるほど、プログラミングにおいてのカプセル化も処理を適切な小箱に分ける事が必要とされているようです。しかし処理を適切な単位に分割することはOOP以前のプログラミングであっても行われてきた手法であります。OOPにおけるカプセル化には何が求められているのでしょうか?またそれによってシステム全体にどんな恩恵がもたらされるのでしょうか?
「自分の機能を使ってくれる他のプログラム」に対しての「配慮」が「安全なシステム」を作る
先にこれらの問いに対するざっくりとした答えを以下に述べます。
- OOPにおけるカプセル化は、分割した処理を「その処理を利用してくれる他のプログラム」に対して「公開する」OR「隠ぺいする」という手法を自身のプログラムに対して盛り込む事である
- これは他者に対して「余計な処理を見せて惑わせない」「処理の意図しない使われ方をさせない」という配慮である
- この「配慮」がオブジェクト(≒プログラム)同士の信頼関係を築きあげ、安全なシステムを作る土台となる
続いて、以下にプログラムのソースを2つ用意しました。一つ目は「適切なカプセル化が行われているソース」です。二つ目は「適切なカプセル化が行われていないソース」です。これら二つは同じ処理を行います。処理の内容としては、
- 二つの商品クラスというものがある(商品AAAと商品BBB)
- これらの商品クラスはコンストラクタとして商品コードを受け取って、DBに格納されている商品情報を自分自身のオブジェクト内部に保持する
- 自身が持っている各商品情報を他者からの求めに応じて出力する
という処理をおこなうプログラムです。
①適切なカプセル化が行われているソースの例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
//★★★適切なカプセル化が行われているプログラム★★★ public class 商品AAA { private String 商品コード; private String 商品名称; private double 消費税率; private double 商品金額税抜; private double 商品金額税込; //コンストラクタ public 商品AAA(String arg商品コード) { 商品コード = arg商品コード; 商品名称 = DBからの商品名称取得処理(arg商品コード); 消費税率 = DBからの消費税率取得処理(); 商品金額税抜 = DBからの商品金額取得処理(arg商品コード); 商品金額税込 = 商品金額税抜 + (商品金額税抜 * 消費税率); } public String get商品コード() { return 商品コード; } public String get商品名称() { return 商品名称; } public double get商品金額税抜() { return 商品金額税抜; } public double get商品金額税込() { return 商品金額税込; } } |
②適切なカプセル化が行われていないソースの例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//★★★適切なカプセル化が行われていないプログラム★★★ public class 商品BBB { public String 商品コード; public String 商品名称; public double 消費税率; public double 商品金額税抜; public double 商品金額税込; //コンストラクタ public 商品BBB(String arg商品コード) { 商品コード = arg商品コード; 商品名称 = DBからの商品名称取得処理(arg商品コード); 消費税率 = DBからの消費税率取得処理(); 商品金額税抜 = DBからの商品金額取得処理(arg商品コード); 商品金額税込 = 商品金額税抜 + (商品金額税抜 * 消費税率); } } |
上記①②両者の違いは「自分の機能を利用してくれる他のプログラム」に対する「配慮」の違い
まず両者のソースコードの4行目~8行目の先頭のプログラムに注目してください。上記①は「private」で処理を隠ぺいしていることに対して、上記②は「public」で処理を公開しています。さらに①は18行目~33行目のプログラムで処理を公開しています。重ねてですが、この両者のプログラムは同じ機能を持っています。しかし「他のプログラムからこれら両者の機能が使われた場合」に違いが現れてきます。この違いがシステム全体の安全性に大きな影響を及ぼします。以下のソースコードで上記①②の機能を呼び出すことによって、実際にその違いを見ていきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//★★★上記①②の機能を利用するプログラム★★★ public class サンプルプログラム { public static void main (String[] args) { String 商品コード = "1234" //---- 商品AAA aaa = new 商品AAA(商品コード); System.out.println(aaa.get商品コード()); System.out.println(aaa.get商品名称()); System.out.println(aaa.get商品金額税抜()); System.out.println(aaa.get商品金額税込()); //---- 商品BBB bbb = new 商品BBB(商品コード); System.out.println(bbb.商品コード); System.out.println(bbb.商品名称); System.out.println(bbb.商品金額税抜); System.out.println(bbb.商品金額税込); bbb.商品名称 = "勝手な名前"; //←このコードには問題がある System.out.println(bbb.商品名称); //---- } } |
19行目のコードが問題となります。bbb.商品名称に「データをセットできてしまうこと」が問題となります。クラス①「商品AAA」②「商品BBB」は、商品コードを初期パラメータとしてDBから取得した各商品情報を内部に保持しつつ、外部からの求めに応じてデータを提供することを役割としています。これらのプログラムには各商品情報を間違いなく管理する責任があるはずです。ところが②「商品BBB」は、上記19行目のコードで自分が責任を持って管理すべきデータである商品名称に外部から勝手な値のセットを許してしまっているのです。この場合オブジェクトの変数である19行目のbbbは誤った値を保持し続けることになります。単なるデータの器であれば問題はありませんが、このオブジェクトが正しい商品データを保持し続ける責任を果たしているとはいえないでしょう。ちなみにクラス①「商品AAA」に関しては、これに対して配慮がなされており商品名称に勝手なデータをセットすることはできません。この配慮こそが「適切なカプセル化」なのです。
すなわちクラス①「商品AAA」は、
- 4行目~8行目のデータ格納項目を「private」というアクセス修飾子で外部から隠蔽し、
- データを提供する窓口をget商品名称という「出力しかできないメソッド」を用いてデータの入出力方向を制限する
上記2点のカプセル化手法を取り入れることで安全性の高いシステム構成要素の一部としての貢献しているのです。
オブジェクトには他者に自分の機能を正しく提供する「責任」がある
OOPのカプセル化手法によって「自分の機能を使ってくれる他のプログラム」に対して「安全な機能の提供」の為の取り組みが行われていることをご理解いただけたと思います。本連載の第一回で私は「OOPで共通化したい事柄は”責任”です」と申し上げました。カプセル化もこの責任を果たすための仕組みなのです。各オブジェクトには他者に対して「余計なものを見せて惑わせない」「意図しない使われ方をさせない」という仕組みを自分のプログラミングに取り入れることによって、自身の機能を正しく提供することへの「責任」が求められているのです。
【本連載について】
- OOPと非OOPの違い|オブジェクト指向プログラミング(OOP)をおさらいしよう(1)
- 継承によってコードを再利用する|オブジェクト指向プログラミング(OOP)をおさらいしよう(2)
- インターフェースとは?~継承とは役割が違う~|オブジェクト指向プログラミング(OOP)をおさらいしよう(3)
- カプセル化とは?~安全なシステムを作る為の配慮~|オブジェクト指向プログラミング(OOP)をおさらいしよう(4)
- 静的型付けと動的型付け~JavaとJavaScriptのJSON処理を比較~|オブジェクト指向プログラミング(OOP)をおさらいしよう(5)