経営・プログラミングを学ぶ あーべるBLOG

経営やプログラミングの便りを呟きます。☆をつけたり読者になってくれたりすると跳ねて喜びます。

Javaでオブジェクト指向をマスターしよう!-カプセル化編-

javaオブジェクト指向
前回はインスタンス、およびコンストラクタについて学習しました。

 

ここまで、クラスは設計図、インスタンスはクラスから生成する実体であることを学んできました。またインスタンスは1つのクラスから複数生成可能であることも前回説明した通りです。

さて、前回の最後に「フィールドの値を直接設定、参照するのはオブジェクト指向では推奨されていない」と言いましたが、今回はその点について解説します。

なお、以下の実行環境を前提にしています。
OS:Windows 10 Pro
IDEEclipse 4.8 Photon(Pleiades
Java:Java8

 

目次

1.カプセル化

今回はカプセル化について学習していきます。カプセル化を理解するコツは、「カプセル化しなくてもプログラムは組める」が、「カプセル化するとメリットがある」点を理解することです。ここからは前回より更に概念的な話になるので難解になりますが、なるべく分かりやすく説明します。

(1)カプセル化とは

カプセル化とは、「関連するデータと操作を一つの単位にまとめる」ことと「プログラムの実現手段を隠ぺいし、外部には操作方法のみを提供する」ための手法のことです。一つずつ見ていきましょう。

(2)関連するデータと操作を一つの単位にまとめる

これに関しては、実は前々回のクラス設計で既に作っていました。データは「フィールド」、操作は「メソッド」および「コンストラクタ」のことです。Humanクラスを見てみましょう。

public class Human {
  //ここがデータ(フィールド)
  String name;
  double height;
  double weight;
  int age;

  //コンストラクタも操作
  Human(String name, double height, double weight, int age) {
    this.name = name;
    this.height = height;
    this.weight = weight;
    this.age = age;
  }
  //ここが操作(メソッド)
  String teachName() {
    return "私の名前は" + name + "です。";
  }
  String teachHeight() {
    return "私の身長は" + height + "センチです。";
  }
  String teachWeight() {
    return "私の体重は" + weight + "キロです。";
  }
  String teachAge() {
    return "私は" + age + "歳です。";
  }
}

データと操作がクラスという単位の中で一つになっています。これがカプセル化の一つ目の特徴です。

プログラムにおいて、操作を定義するためのアルゴリズムと、そのアルゴリズムに適したデータ構造は切り離すことができないことが大半です。例えば、int型配列を繰り返し処理ですべて合算するアルゴリズムを想像してみてください。

int[] intAry = {1, 3, 6, 11, 4};
int total = 0;
for (int i : intAry) {
  total += i;
}
System.out.println(total); //25

繰り返し処理がアルゴリズムで、int型配列がアルゴリズムに適したデータ構造です。この場合どちらか一つを変えようとしても変えられないほど、アルゴリズムとデータ構造が依存しあっている関係にあります。これを踏まえると、アルゴリズムとそれに依存したデータ構造は別々に管理するより、一つの場所で管理した方がどちらかに修正が生じる場合も変更箇所が管理場所の内部でだけの話になるので、保守管理しやすいのです。オブジェクト指向では、アルゴリズムとデータ構造をクラスを使って「カプセル化」して、一つの場所に密閉しています。

 

(3)内部情報の隠蔽

オブジェクト指向では、プログラム内部の設計は公開せず、操作方法のみを外部に公開すべきという考え方があります。オブジェクトの利用者には機能の使い方だけ見せて、その機能の実現方法は必要ない情報なので、隠ぺいするのが正しいという概念です。

例えばスマートフォンを想像してみましょう。スマートフォンは電話やSNS、メール、音楽・動画再生など多くの機能がありますが、私たちはスマートフォンがどうやってその機能を提供しているのか、内部でどんなシステムが動いているか分かりません。しかし、分からなくてもスマートフォンを使うことはできますよね。この「実現方法は分からなくても操作できる」が重要なポイントです。

Javaであらかじめ用意されているクラスはほとんどがカプセル化されています。例えば、JavaArrayListは後から要素を追加していき、内部で持っている配列の長さが足りなくなると、新しく元の配列の1.5倍の長さの配列を生成して元の配列からデータをコピーしています。しかし、私たちはこんなこと知らなくてもaddメソッドを呼べば要素を追加でき、getメソッドを呼べば要素を参照できることを知っています。内部で配列をどう扱っているか、どんなアルゴリズムが組まれているかを知る必要は無いのです(実際は知っていると処理の負荷を下げることができますが、ここでは内部詳細を知らなくてもArrayListは使えるという点を重視しています)。

オブジェクト指向では、アクセス修飾子を使ってこの状態を作り出します。

(4)Humanクラスをカプセル化する

では実際にカプセル化してみましょう。現時点で「データと操作を一つにまとめる」方はできているので、ここでは「内部情報の隠ぺい」を追加していきます。具体的には、フィールドを「private」にして情報を隠ぺいし、メソッドおよびコンストラクタを「public」にします。

public class Human {
  private String name;
  private double height;
  private double weight;
  private int age;

  public Human(String name, double height, double weight, int age) {
    this.name = name;
    this.height = height;
    this.weight = weight;
    this.age = age;
  }

  public String teachName() {
    return "私の名前は" + name + "です。";
  }

  public String teachHeight() {
    return "私の身長は" + height + "センチです。";
  }

  public String teachWeight() {
    return "私の体重は" + weight + "キロです。";
  }

  public String teachAge() {
    return "私は" + age + "歳です。";
  }
}

こうすることで内部情報は隠ぺいされ、内部情報にアクセスするための操作だけが残ります。

2.まとめ

先ほどもお話ししましたが、カプセル化はしなくても動くプログラムを組むことはできます。しかし、操作と、操作に関連するデータを同じ場所で管理することや、オブジェクトの利用者に必要な操作のみを提供し情報を隠蔽することで、プログラムの可読性や保守性が向上し、修正しやすいシステムにしていくことが可能です。オブジェクト指向はシステムを「仕様変更に強くする」のが目的でした。カプセル化は、オブジェクト指向には無くてはならない存在です。

次回は「継承」について解説します。継承もカプセル化同様、オブジェクト指向を理解する上で非常に重要な概念です。継承を覚えることで、さらに仕様変更に強いシステムを作れるようになりますので、オブジェクト指向の恩恵をより多く受けられるようになります。