Hello Worldからの復習　～カプセル化編～

Spotifyで落語を聞くのが趣味だが、いろんな噺家さんがランダムに聞けて良い。
去年、おととしあたりは、春風亭一之輔にはまり、笑点に出演が決まったとき、笑点の見方も知っている噺家さんが出るようになるとまた違った感じで見れる気がする。
まぁ最近テレビを破棄したのでテレビ自体観ていないのだが、、
最近聞いて話し方面白いなぁと感じているのは「桃月庵白酒」で師匠は五街道雲助。
師匠の亭号を継ぐ人もいれば改める人もいるんだな。
歌舞伎だと代々受け継ぎ格式高い印象がある。(落語が格式低いとは言っていませんw)
落語の亭号は割と自由なんだなと感じた。
歌舞伎は屋号、名跡、格で枠が決まり生まれた家系でカチッとしていて、落語は家系というより噺家になりたいという人が弟子入りしてっていう感じで割とパブリックな感じ。
歌舞伎も養成所から入ったりと家系外もたまにあるが、どちらかというとprotected、privateなところがあるなと思いましたというお話。

ペコリ



##### カプセル化って？
+ メリットは？
+ Sample
---
◆カプセル化って？
-

**アクセス修飾子**でクラス・メンバー変数・メソッドの公開範囲を指定できる。

| 修飾子 | 同クラス | 同パッケージ | サブクラス | その他 |
|:-:|:-:|:-:|:-:|:-:|
| public  | 〇  | 〇  |  〇 |  〇 |
|  protected  |  〇 | 〇  | 〇  |   |
|  (なし) | 〇  | 〇  |   |   |
|  private | 〇  |   |   |   |

・メンバー変数は隠蔽(private)して、クラスとメソッドは公開(public)する設計方針を**カプセル化**という。


```java:java
class Student{
  private int score;
  public void setScore(int s){
  .
  .
  score = s ;
  }
}
```
▼
```cmd:Y or N
〇 stu.setScore(80); ✕ stu.score = 80;
```
上記の✕のようにメンバー変数に対して直接アクセスするような書き方は、private指定されているため、コンパイル時点でエラーになる。


メリットは？
-
**代入前処理**
メンバー変数に値を設定する場合。
値の代入をするときにsetScoreメソッドを使って、この中で例えば0～100までかどうかをチェックするみたいな。
実際に代入する前に正しい値かどうかをチェックするようなことができるようになる。
stu score = 80のようにどんな値が入るかわからない。
それを変数への直接代入をprivateで禁止してメソッドを通じてのみ値が代入できるように設定しておくと、不正な値が入るのを防ぐことができるのがメリットの1つ。

**修正範囲が狭まる**
privateを指定したプログラムを作っていれば、scoreの変更はこのクラスの中だけ。
privateのscoreの情報は外に出てこないため、scoreの修正はこのクラスの修正だけに範囲が限られる。
メンテナンスのしやすさがメリット

◆Sample
-

privateを設定しない。


```java:java
public class Student5{
  private String name;
  int score;

  public Student5(String n){
    name = n;
  }
  public void setScore(int s){
    if(0 <= s && s <= 100){ //0～100までかどうか。
      score = s;
    } else {
      System.out.println(name + "さんの点数が範囲外です");
      score = 0;
    }
  }
  void display(){
    System.out.println(name + "さん：" + score + "点");
  }
}

```

```java:java
class StuSample5{
  public static void main(String[] args){
    Student5 stu1 = new Student5("大輔");
    stu1.setScore(80);
    stu1.display();
    
    Student5 stu2 = new Student5("湊丞");
    stu2.setScore(-50); //範囲外の値
    stu2.display();
  }
}
```

```cmd:cmd
C:\Java\1>java StuSample5
大輔さん：80点
湊丞さんの点数が範囲外です
湊丞さん：0点 //範囲外はデフォルトの0が与えられる
```

ふーん。
代入された値が入っていて、0～100が範囲だから-50は範囲外でデフォルトの0が表示された。

これが、範囲外の値が入っちゃうと

```java:java
class StuSample5{
  public static void main(String[] args){
    Student5 stu1 = new Student5("大輔");
    stu1.setScore(80);
    stu1.display();
    
    Student5 stu2 = new Student5("湊丞");
    //stu2.setScore(-50);
    stu2.score = -50; //直接メンバー変数にアクセス
    stu2.display();
  }
}
```

```cmd:cmd
C:\Java\1>java StuSample5
大輔さん：80点
湊丞さん：-50点
```
メンバー変数にprivate指定していないため、直接アクセスで値が代入できてしまう。

設計図クラスの担当者が`.setScore`で呼び出してねと言っても、呼び出す側が`.score`で代入できてしまう状態になる。
まぁ、ちゃんと`setScore`で呼べば良いんだけど、そもそも代入できない方が良いので、、

未然に防げる方法が**private指定**

pivate指定Sample
-
```java:java
public class Student5{
  private String name;
  private int score; //メンバー変数にprivate指定する

  public Student5(String n){
    name = n;
  }
  public void setScore(int s){
    if(0 <= s && s <= 100){ //0～100までかどうか。
      score = s;
    } else {
      System.out.println(name + "さんの点数が範囲外です");
      score = 0;
    }
  }
  void display(){
    System.out.println(name + "さん：" + score + "点");
  }
}

```
```cmd:cmd
C:\Java\1>javac StuSample5.java
StuSample5.java:9: エラー: scoreはStudent5でprivateアクセスされます
    stu2.score = -50;
        ^
```
コンパイル時点でエラーが出ます。

修正するときもメンバー変数の名前変更だけで済むとか、そんなもんで修正が終わるのでラク。
直接アクセスだとアクセスする側の修正も必要になるため、手間が増えるし、エラーも出やすくなるので指定した方がよい。

一般的にはメンバー変数にはprivate指定、メソッドにはpublic指定して、メソッドを経由してメンバー変数を利用したり、設定したりする。