オブジェクト指向を利用する理由として、プログラミングの入門書には
「オブジェクト指向を用いると、現実世界をプログラミングでそのまま表現できる」
という意のことが書いてあることが多いです。
その例として
- 犬に「ワン」と鳴かせ、猫に「ニャーン」と鳴かせる
- 乗用車に普通に走らせ、レーシングカーに速く走らせる
といった例が用いられることが多いです。
しかし、実務での使われ方を見ると
「現実世界をプログラミングでそのまま表現する」
というのは、目的ではなく手段と言うべきものです。
実務では
「ソースコードから重複を取り除き保守性を高めるため」
という目的で使用されます。
現実世界の関係性を機械の都合に置き換えると、ソースコードに重複が発生しやすくなります。
そこで、「継承」や「ポリモーフィズム」(同じメソッド名の指定でオブジェクト毎に異なる処理をさせること)といった特徴を持つオブジェクト指向を適用することで、現実世界の関係性をそのまま記述することができるようになり、重複の発生を防ぐことができるようになります。
(同じく、オブジェクト指向の特徴として挙げられる「カプセル化」も、オブジェクト指向のルールを守らせるという意味で強力な特徴です)
目的が保守性の向上であるため、現実世界では意識されにくい「思考ルーチン」「出力機能」といったものも、クラス化されることがあります。
また、保守性の向上に繋がらないのであれば、現実世界にあるものをクラスとして記述しないこともあります。
重複を取り除くことによる保守性向上、というのはイメージしにくい所だと思いますので、以下ではJavaのサンプルコードを用いて説明していきます。
今回のサンプルコードでは、「乗り物に乗って、タイミングを見計らって、乗り物を走らせる」という処理を実装していきます。
「乗り物に乗る」という処理と「乗り物を走らせる」という処理は別々のタイミングで実行する必要があるので、別々に実装する必要があります。
また、乗り物は複数種類があり、それぞれの種類毎で異なる処理を行う必要があるとします。
オブジェクト指向を使用しない場合は、下記に示すようなサンプルコードになります。
【オブジェクト指向を使用しない場合のサンプルコード】
・OOPTestMain.java
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 35 36 37 38 39 40 41 42 43 44 45 46 47 |
public class OOPTestMain { public static void main(String[] args) { // 自動車を定義 int vehicleFlag = 1; // 乗る動作 ride(vehicleFlag); // 準備(5秒待つ) System.out.println("準備中です…"); try { Thread.sleep(5 * 1000); } catch (InterruptedException e) { } // 走る動作 run(vehicleFlag); } public static void ride(int vehicleFlag) { // 自動車の場合 if (vehicleFlag == 1) { System.out.println("ドアを開けて運転席に座る"); // 自転車の場合 } else if (vehicleFlag == 2) { // 自転車を示すフラグを2から3に変更する場合の変更箇所 System.out.println("またがる"); } } public static void run(int vehicleFlag) { // 自動車の場合 if (vehicleFlag == 1) { System.out.println("アクセルを踏み込む"); // 自転車の場合 } else if (vehicleFlag == 2) { // 自転車を示すフラグを2から3に変更する場合の変更箇所 System.out.println("ペダルをこぐ"); } } } |
【サンプルコードの実行結果】
1 2 3 4 |
ドアを開けて運転席に座る 準備中です… アクセルを踏み込む |
「乗り物に乗る」という処理と「乗り物を走らせる」という処理は、別々のメソッドとして実装しています。
乗り物の種類毎で処理を分ける必要があり、オブジェクト指向を使用しないサンプルコードではフラグ変数により分けています。
注目するべきは、各々のメソッドの中でフラグ変数を参照していることです。
各々のメソッドの中でフラグ変数を参照しているため、フラグ変数を参照する箇所はメソッドの数だけ存在することになります。
フラグ変数の参照方法が変更される場合、例えば「自転車」を示すフラグが2から3に変更になる場合、修正する箇所もメソッドの数だけ存在することになります。
(具体的な修正箇所はサンプルコード中にコメントで示した通りで、今回の場合は2か所です)
修正箇所が増えることで保守性が低下します。具体的には、修正漏れのようなミスが発生しやすくなります。
サンプルコードにオブジェクト指向を適用すると下記のようなコードになります。
【オブジェクト指向を使用する場合のサンプルコード】
・OOPTestMain.java
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 OOPTestMain { public static void main(String[] args) { // 自動車を定義 OOPTestVehicle vehicle = new OOPTestCar(); // 乗る動作 vehicle.ride(); // 準備(5秒待つ) System.out.println("準備中です…"); try { Thread.sleep(5 * 1000); } catch (InterruptedException e) { } // 走る動作 vehicle.run(); } } |
・OOPTestVehicle.java
1 2 3 4 5 6 |
public interface OOPTestVehicle { public void ride(); public void run(); } |
・OOPTestCar.java
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class OOPTestCar implements OOPTestVehicle { @Override public void ride() { System.out.println("ドアを開けて運転席に座る"); } @Override public void run() { System.out.println("アクセルを踏み込む"); } } |
・OOPTestBicycle.java
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class OOPTestBicycle implements OOPTestVehicle { // 自転車を示すクラス名を変更する場合の変更箇所 @Override public void ride() { System.out.println("またがる"); } @Override public void run() { System.out.println("ペダルをこぐ"); } } |
注目するべきは、ポリモーフィズムを使用することで、フラグ変数参照に相当する記述を削減できていることです。
フラグ変数の参照に相当する処理としては、クラス名の参照がありますが、クラス名に変更が発生したとしても修正箇所は1カ所に留まるため、保守性が向上します。
今回の記事は、Javaプログラマーとして活躍し始めた後に意識するべき内容であり、入門レベルよりも少し高度なものになります。
しかし、意識するのとしないのとでは、プログラムをリリースした後の保守のしやすさが変わってきます。
指示されたものを作って終わりではない、お客様からの信頼を得られるシステムを主体的に作るためには、こうした設計思想も学ぶ必要があります。
設計思想を学ぶ上では、前提知識として、プログラミング言語の基礎的の文法の理解が必要になります。
先日弊社から発売した書籍「絶対にJavaプログラマーになりたい人へ」で基礎的な文法の理解を固めることで、今回のような設計思想の話も理解しやすくなるのではないかと思います。
(興味がある方は是非とも購入のご検討を!)
コメント