2014年10月13日月曜日

- カプセル化 - Java

今日から、三大要素について学んでいく。

三大要素を、非常にざっくりまとめた。
























詳細は、学んで、もしくは使って理解出来たらいいと思います。

今日、学習する「カプセル化」は、いわば、守りの要。
いったい、何から守るかというと、不具合です。

開発現場では、不具合への対応に多くの時間がさかれています。
もちろん、カプセル化だけでは、全ては防げないけれど、あるのとないのとでは、大きな違いがある。


カプセル化ってなに?ということろから。

カプセル化 とは フィールドへの読み書きや、メソッドの呼び出しを制限する機能
キーワードは「制限」です。

現実世界で考えてみると……
・家に鍵をかけるようなもの
・赤ちゃんがいる家で、包丁が入っている扉を子どもの能力では開けられないようにするようなもの

もし、家に鍵をかけなかったら……赤ちゃんが自由に扉を開け閉め出来たら……。
思わぬ事故や、危険が発生する可能性がありますね。

カプセル化は、その事故や、危険を未然に防ぐためのものである。

このような「制限」を「アクセス制御 (access control)」という。

このアクセス制御は、メンバ(フィールド、メソッド)とクラスに設定が行える。

メンバへのアクセス制御

メンバ(フィールド、メソッド)に対するアクセス制御は四段階ある。


















private,public などを アクセス修飾詞 (access modifier) という。
フィールドや、メソッドを宣言する際に、先頭につける。

さっそく、 private を使ってみる。


package blog;

public class Tomomi {

 // アクセス修飾詞 private をつけたフィールドを宣言
 private int birthday;
 private String name  = "ともみ";

 void congratulate (){
  this.birthday = 1020;
  System.out.println(this.name +"の誕生日"+this.birthday + "には、お祝いをしよう!");
 }

}

package blog;

public class main {

 public static void main(String[] args){

 Tomomi  t = new Tomomi();

 t.congratulate();

 }
}









とくに、難しいことはない。

private をつけることにより、 フィールド birthday name は、他のクラスから書き換えることは出来なくなった。


実は、このアクセス制御は、だいたい使い方が決まってる

・フィールドは private
・メソッド(あと、クラス)は public

(ただし、テストをする際に、フィールドにアクセス出来ないと不都合が生じるため、なんでもprivateにすればいいわけではない。)

ここで、一つ問題が生じる。
これだと、フィールドを別のクラスからアクセスができない。

これだけでは、出来ないけれど
メソッドを経由してアクセスする方法がある。

 getter と setter 

getter メソッド と setter メソッド というものを作って、それを経由してフィールドにアクセスをする。
そうすると、フィールドの値に不具合が生じた場合、経由しているメソッドを調べれば、原因が特定できたりする。












前に、簡単に作っていて、我が家の近所の進化系をgetterメソッドを使って作ってみた。
setterメソッドを取り入れるのを失念していたため、今回はgetterメソッドのみで。
そのうち、setterメソッドを取り入れたものを作る。


package blog;

import java.util.Random;

public class StrayCat {

  String name = "野良猫ちゃん";

  // private である int型の変数 hungryPoint を宣言
  private int hungryPoint;

  // hungryPoint に 1~10 までの乱数を代入するメソッド
  void calcHungryPoint(){
   hungryPoint = new Random().nextInt(9)+1;
  }

  // private である int型の変数 hungryPoint を受け取るためのメソッド
  public int getHungryPoint(){
   return hungryPoint;

  }
  void cadge (){
   System.out.println(this.name + "は餌をねだった");
  }
  void eat (){
   System.out.println(this.name + "は、餌を食べた");
  }
  void escape (){
   System.out.println(this.name + "は、逃げ出した");
  }
}


package blog;

public class FeederLady {

  String name = "餌やりおばさん";

  void feed (){
   System.out.println(this.name + "は餌をあげた");
  }
  void escape (){
   System.out.println(this.name + "は逃げ出した");
  }
}


package blog;

import java.util.Random;

public class NextHouseLady {

  String name = "隣のおばちゃん";

  // private である int 型の変数 ragePoint を宣言
  private int ragePoint;

  // ragePoint に 1~10 までの乱数を代入するメソッド
  public void calcRagePoint(){
   ragePoint = new Random().nextInt(9)+1;
  }

  // private である int型の変数 ragePoint を受け取るgetterメソッド
  public int getRagePoint(){
   return this.ragePoint;
  }

  void rage (){
   System.out.println("おばちゃんは、激怒した!!");
  }
}

package blog;

public class main {

 public static void main(String[] args) {
  // TODO 自動生成されたメソッド・スタブ

  // 三つのクラスをインスタンス化
  StrayCat c = new StrayCat();
  FeederLady f = new FeederLady();
  NextHouseLady n = new NextHouseLady();

  // 先に乱数を生み出す calcHungryPointメソッドを呼び出す
  c.calcHungryPoint();
  System.out.println(c.name + "の空腹度は" + c.getHungryPoint() + "です");

  // getHungryPointが5以下の場合は終了
  if (c.getHungryPoint() < 5) {
   return;
  }

  // getHungryPointが5以下ではない場合に以下のメソッドを呼び出す
  c.cadge();
  f.feed();
  c.eat();

  // 先に乱数を生み出す calcRagePointメソッドを呼び出す
  n.calcRagePoint();
  System.out.println(n.name + "の不機嫌度は" + n.getRagePoint() + "です");

  // getRagePointが5以下の場合は終了
  if (n.getRagePoint() < 5) {
   return;
  }

  // getRagePointが5以下ではない場合は以下のメソッドを呼び出す
  n.rage();
  c.escape();
  f.escape();
 }

}
















これを使うことの利点は主に三つある

①ReadOnly,WriteOnlyのフィールドを実現できる
②フィールドの名前など、クラス内部設計を自由に変更できる
③フィールドへのアクセスを検査できる
   (たとえば、禁止ワードなどを、入力された時点ではじく設計に出来る。setterメソッドが重要)


クラスのアクセス制御

クラスに対するアクセス制御は二段階ある。











package privateクラスには特徴がある

①クラスの名前がソースファイルと一致しなくてもよい
②一つのソースファイルに複数宣言できる



これで、カプセル化についての学習は終わり。
使い方は簡単だけど、使いどころが大変難しい。
大規模開発の場合は、定められている方針に従ってカプセル化を使い分けると思います。
わたしが作るレベルでは、テストはあまりやらないので(やったほうがいいけど)基本的にフィールドをprivateにしてしまおうかなーと考えてます。

0 件のコメント:

コメントを投稿