オブジェクト指向中級入門

# 目的

オブジェクト指向プログラミングは分かるけど、なんか使いこなせてない方へ
難しいことは抜きに、コード見てアハ体験が少しでもしてもらえらたらうれしいポエム

# こんな人に良いかも

* オブジェクト指向プログラミングの基本はわかってる。
* ポリモーフィズムしてもIf分が減ってると感じない。
* デザインパターンは何となく分かるけど使いこなせない。
* SOLID原則とかなんとなく知ってるけど使いこなせてるかわからない。
* オブジェクト指向で共通化のロジックがなんかいつも歪。

# オブジェクト指向プログラミングの迷宮

まずはよくある迷宮に入ってみましょう。

## カレーを作るプログラムを書く

まずはコードを書きましょう。

仕様は、この通り。
* 野菜切って肉と鍋に入れて、炒めるなり煮込むなりしてカレー粉投入。
* 家庭によってレシピが少し変わります。
* 今回は、田中家と佐藤家のカレーを作る。
* 田中家と佐藤家の違いは、炒めて煮るか。ただ煮るか。だけです。

## コード

```java

class CurryMaker {

  String make(
      String familyId,
      String carrotId, String potatoId, String onionId, String meatId
  ) {

    // 1. 野菜を切ったり
    人参を切る(carrotId); // 何かしらをするメソッドが呼ばれてます
    ジャガイモを切る(potatoId);
    玉ねぎを切る(onionId);
    String vegetablesId = ボウルに入れる(carrotId, potatoId, onionId);

    // 2. 鍋に入れて煮込む
    String potId = 鍋を取り出す();
    if (familyId.equals("佐藤")) { // ここがプログラムのポイントです!
      鍋に投入(potId, vegetablesId, meatId);
      炒める(potId);
      煮込む(potId);
    } else if (familyId.equals("田中")) {
      鍋に投入(potId, vegetablesId, meatId);
      煮込む(potId);
    }

    // 3. ルーを投入して煮込んで完成
    String curryPowderId = カレー粉を取り出す();
    鍋に投入(potId, curryPowderId);
    煮込む(potId);

    // カレーが入った鍋
    return potId;
  }
}

```
そこまで悪くない気がします。オブジェクト指向プログラミングしてないですが。
プログラムを拡張していきましょう。

## 鈴木家のカレーに、ルーは使わない

本格派の鈴木家は、市販のカレールーなどという軟弱なものに頼りません。
独自にスパイスを調合して使うそうです。

## コード

```java

class CurryMaker2 {

  String make(
      String familyId,
      String carrotId, String potatoId, String onionId, String meatId
  ) {

    // 1. 野菜を切ったり肉を切ったり
    人参を切る(carrotId);
    ジャガイモを切る(potatoId);
    玉ねぎを切る(onionId);
    String vegetablesId = ボウルに入れる(carrotId, potatoId, onionId);

    // 2. 鍋に入れて煮込む
    String potId = 鍋を取り出す();
    if (familyId.equals("佐藤") || familyId.equals("鈴木")) { // よく見てくださいここが肝です!!
      鍋に投入(potId, vegetablesId, meatId);
      炒める(potId);
      煮込む(potId);
    } else if (familyId.equals("田中")) {
      鍋に投入(potId, vegetablesId, meatId);
      煮込む(potId);
    }

    // 3. ルーを投入して煮込んで完成
    if(familyId.equals("鈴木")) {  // よく見てくださいここが肝です!!
      String currySpiceId = カレースパイスを調合する();
      炒める(currySpiceId);
      鍋に投入(potId, currySpiceId);
    }else { // ようするにここはどの家族？
      String curryPowderId = カレー粉を取り出す();
      鍋に投入(potId, curryPowderId);
    }
    煮込む(potId);

    // カレーが入った鍋
    return potId;
  }
}

```

少し分かりづらくなりました。
二つのif文をうまく追わないと、家庭毎の違いが分かりません。

## abstract CurryMaker で立ち向かう　初級編

ということで、オブジェクト指向プログラミングの迷宮へ出発です。
家庭による違いのごちゃごちゃを排除しましょう。

## みんな大好きテンプレートメソッド

```java

abstract class CurryMaker3 {

  String make(
      String familyId,
      String carrotId, String potatoId, String onionId, String meatId
  ) {

    // 1. 野菜を切ったり下準備
    String vegetablesId = 下準備をする(carrotId, potatoId, onionId, meatId);

    // 2. 鍋に入れて煮込む
    String potId = 鍋を取り出す();
    煮込みをする(potId, vegetablesId, meatId);

    // 3. ルーを投入して煮込んで完成
    カレーの仕上げ(potId);

    // カレーが入った鍋
    return potId;
  }

  protected String 下準備をする(
       String carrotId, String potatoId, String onionId, String meatId
  ) {
    // 略
  }

  protected abstract void 煮込みをする(String potId, String vegetablesId, String meatId);
  protected abstract void カレーの仕上げ(String potId);
}
```
シンプルになりました。

継承していくぜ

```java

class 田中CurryMaker extends CurryMaker3 {
  @Override
  protected void 煮込みをする(String potId, String vegetablesId, String meatId) {
    鍋に投入(potId, meatId, vegetablesId);
    煮込む(potId);
  }
  @Override
  protected void カレーの仕上げ(String potId) {
    String curryPowderId = カレー粉を取り出す();
    鍋に投入(potId, curryPowderId);
  }
}

```
```java

class 佐藤CurryMaker extends  CurryMaker3 {
  @Override
  protected void 煮込みをする(String potId, String vegetablesId, String meatId) {
    鍋に投入(potId, vegetablesId, meatId);
    炒める(potId);
    煮込む(potId);
  }
  @Override
  protected void カレーの仕上げ(String potId) {
    String curryPowderId = カレー粉を取り出す();
    鍋に投入(potId, curryPowderId);
  }
}
```
```java

class 鈴木CurryMaker extends  CurryMaker3 {
  @Override
  protected void 煮込みをする(String potId, String vegetablesId, String meatId) {
    鍋に投入(potId, vegetablesId, meatId);
    炒める(potId);
    煮込む(potId);
  }
  @Override
  protected void カレーの仕上げ(String potId) {
    String currySpiceId = カレースパイスを調合する();
    炒める(currySpiceId);
    鍋に投入(potId, currySpiceId);
  }
}

```

悪くはない気がしますね。

## if消えてないから

よくある記事だと、わーいif文が消えました。と、終わらせますが

```java

void main () {
  if (familyId.equals("佐藤") ) {
    new 佐藤CurryMaker().make(/*略*/);
  } eles if (familyId.equals("鈴木")) {
    new 鈴木CurryMaker().make(/**/);
  } else if (familyId.equals("田中")) {
    new 田中CurryMaker().make(/**/);    
  }
}
```
消えてはないですね。

## 破綻1

高橋家は、佐藤家とカレー粉だけ違うんだ。

```java

abstract class 佐藤CurryMakerBase  extends カレーメーカー{
  @Override
  protected void 煮込みをする(String potId, String vegetablesId, String meatId) {
    鍋に投入(potId, vegetablesId, meatId);
    炒める(potId);
    煮込む(potId);
  }
  @Override
  protected void カレーの仕上げ(String potId) {
    String curryPowderId = カレー粉を取り出す();
    鍋に投入(potId, curryPowderId);
  }

  // 抽象メソッドを追加!!
  abstract String カレー粉を取り出す();
}

class 高橋CurryMaker extends 佐藤CurryMakerBase {
  @Override
  String カレー粉を取り出す() {
   /*略*/
  }
}

//もちろん、佐藤CurryMakerの実装クラスも必要ですが、略。
```

さらなる継承をしました。

今回は、継承をするには極端な例ですね。
ですが、継承はさらなる継承による拡張が始まります。

```
BaseHoge -> BaseQueryHoge  -> NageQueryHoge
         -> BaseUpdateHoge -> DageUpdateHoge
                           -> SageUpdateHoge 
```

## 破綻2

中村家は、少し変わっていて、煮込む前にルーを投入するんだ。

```java

class 中村CurryMaker extends  CurryMaker3 {
  @Override
  protected void 煮込みをする(String potId, String vegetablesId, String meatId) {
    鍋に投入(potId, vegetablesId, meatId);
    炒める(potId);
    String curryPowderId = カレー粉を取り出す(); //もうここでカレー入れちゃうの!!
    鍋に投入(potId, curryPowderId);
    煮込む(potId);
  }
  @Override
  protected void カレーの仕上げ(String potId) {
    /* do nothing */ //何もしないことを表現してます!!
  }
}
```
歪の痛みを感じて来ましたね。
baseクラスを修正するときは中村家を忘れるとあぶなそうですね。

中村家のせいで俺のクラスが、、、

## 迷走のゴール

迷走できましたでしょうか。
まだまだこのぐらいだと許されることが多いでしょうか。

システムが複雑になっていくと、少しだけ異なるパターンが増えます。
「この時だけメール送りたい。」「この時だけチェックしたい。」

「少しだけ異なる」について、継承をベースにしていると、最も自然な手段はさらに継承を重ねることです。
中村家のように親と異なるモノが出てきて、そのツリーをゆがめていきます。

たくさん継承したいわけではないのです。
必要だから、継承を積みかねて、そして歪な実装をしていく。


オブジェクト指向プログラミングに目覚めるとみんな通る道です。
というか、昔は一般的な拡張の戦略でした。まだまだそこそこ見たりしますね。
InputStream/OutputSreamでぐぐれ。


# 脱abstract 初級++

今どき継承ないわ～な、みなさん、出番です。

```java

class CurryMaker4{
  String make(
      String familyId,
      String carrotId, String potatoId, String onionId, String meatId
  ) {

    // 1. 野菜を切ったり下準備
    String vegetablesId = 下準備をする(carrotId, potatoId, onionId, meatId);
    
    // 2. 鍋に入れて煮込む
    String potId = 鍋を取り出す();
    this.煮込みStrategy.煮込みをする(potId, vegetablesId, meatId);

    // 3. ルーを投入して煮込んで完成
    this.カレーの仕上げStrategy.カレーの仕上げ(potId);

    // カレーが入った鍋
    return potId;
  }
}
```

```java

class 田中煮込みStrategy implements 煮込みStrategy { 
  @Override
  void 煮込みをする(String potId, String vegetablesId, String meatId) {
    鍋に投入(potId, meatId, vegetablesId);
    煮込む(potId);
  }
}
class 田中カレーの仕上げStrategy implements カレーの仕上げStrategy {
  @Override
  void 仕上げ(String potId) {
    String curryPowderId = カレー粉を取り出す();
    鍋に投入(potId, curryPowderId);
  }
}

// if文とか引数は、略
main () {
   new CurryMaker4(
     new 田中煮込みStrategy(),
     new 田中カレーの仕上げStrategy()
   ).make();
}

```

Strategyパターンを導入して、継承を排除しました。

面食らってたデザパタに慣れて、こなれてきたころにあなたは気が付きます。
「ぶっちゃけStrategyがあればだいたいどうにかなる。というか移譲だな。」
開放閉鎖守ってSOLID原則もダダ褒めです。

## 初級++ふりかえり

めでだし。めでたし。これでオブジェクト指向プログラミングマスターだ。

でもね。
でもですね。
これって本当にわかりやすい？

```java

// 何もしないことをすることを表現するクラスです。
class 中村カレーの仕上げStrategy implements カレーの仕上げStrategy {
  @Override
  void 仕上げ(String potId) {
    /* do nothing */ 
  }
}
```
わかりやすい？

## オブジェクト指向とはそういうもの？

初級++を見てみましょう。
大まかな工程が分かるように見えます。ですが、家族毎の工程も読まないと、何をしてるか分かりづらいですね。
クラスはシンプルなように見えますが、関係するクラスを追わないとわからない。

CuryMakerが弄られたら、すべての家庭に影響を与えていく、、
中村家のような家族では。歪さはあまり変わっていない、、、

しかたのない複雑さなのでしょうか。
それともプログラミング技術がまだ不足しているのでしょうか？

悩みながら、さらなるプログラミング技術を取得しようとします。ですが、何故か良い本や情報も出てきません。

オブジェクト指向とはそういうもので、オブジェクト指向を導入する前のコードの方が分かりやすい。と諦めます。
妥協は妥協を呼び寄せ、いつしか手がつけられないほどのごちゃごちゃを生み出していきました。

思い当たる方は、中級入門編に行ってみましょう。

# 中級入門編

洗練されたコードを書くために、コードから少し離れます。
コードを書く人にとって、この辺り最初は非常にハードルが高く感じます。
ですが、騙されたと思って少し離れてみましょう。

## プログラムを知らない人はこう説明する

言葉で整理しましょう。

* カレーを作るとは、カレーの料理工程をこなしていくことである。
* カレーを作る工程は、家族により異なる。
* 野菜を切る下準備や、仕上げの煮込みなど同じ工程もある。
* 以下、家庭のレシピ

```markdown

田中
1. 野菜を切って下準備
2. 鍋に投入して、煮込む
3. カレー粉投入して仕上げ煮込む

佐藤
1. 野菜を切って下準備
2. 鍋に投入して、炒めて煮込む
3. カレー粉投入して仕上げ煮込む

鈴木
1. 野菜を切って下準備
2. 鍋に投入して、炒めて煮込む
3. カレースパイスを調合
4. スパイを投入して仕上げ煮込む

高橋
1. 野菜を切って下準備
2. 鍋に投入して、炒めて煮込む
3. カレー粉投入して仕上げ煮込む ※(カレー粉が佐藤家とは別)

中村家
1. 野菜を切って下準備
2. 鍋に投入
3. カレー粉投入して仕上げ煮込む
```

わかりやすいですね。
今後家庭毎のレシピが増えても普通にまとめられそう。

## そのままコードに書く

わかりやすいなら、そのままコードに書いてみましょう。

```java
class 田中CurryMaker {
  String make(
      String carrotId, String potatoId, String onionId, String meatId
  ) {

    // 1. 野菜を切って下準備
    String vegetablesId = 下準備(carrotId, potatoId, onionId);

    // 2. 鍋に投入して、煮込む
    String potId = 鍋に投入(vegetablesId, meatId);
    煮込む(potId);

    // 3. カレー粉投入して煮込む
    カレー粉投入(potId, カレー粉());
    仕上げ煮込み(potId);
  }

 /* ここに大量の関数の実装がずらずらとならぶ */

}

class 佐藤CurryMaker {
  String make(
      String carrotId, String potatoId, String onionId, String meatId
  ) {
    // 1. 野菜を切って下準備
    String vegetablesId = 下準備(carrotId, potatoId, onionId);

    // 2. 鍋に投入して、炒めて煮込む
    String potId = 鍋に投入(vegetablesId, meatId);
    炒める(potId)
    煮込む(potId);

    // 3. カレー粉投入して煮込む
    カレー粉投入(potId, カレー粉());
    仕上げ煮込み(potId);
  }

 /* ここに大量の関数の実装(田中と同じ実装)がずらずらとならぶ */

}
```

家庭毎のクラスに分かれることに。
それ以外は、初期のコードに似ています。if文が消えたので分かりやすいですね。

しかしながら、継承も共通化もしてないので、重複コードがいっぱいですね。

## 共通化してみる

```java

class 田中CurryMaker {
  String make(
      String carrotId, String potatoId, String onionId, String meatId
  ) {
    // 1. 野菜を切って下準備
    String vegetableId =  new 下準備工程().する(carrotId, potatoId, onionId);

    /*略*/
  }
}

class 佐藤CurryMaker {
  String make(
      String carrotId, String potatoId, String onionId, String meatId
  ) {
    // 1. 野菜を切って下準備
    String vegetableId = new 下準備工程().する(carrotId, potatoId, onionId);

    /*略*/
  }
}

class 下準備工程 {
  String する(carrotId, potatoId, onionId) {
       // 好きなだけ刻む処理をかきまくる
  }
}

```
下準備工程だけ共通化してみました。クラスに分けただけですね。
流れとしては、自然ですね。
ですが、初級編とは大きく異なるクラス構造になります。

## 残りもやってみよう

田中

```java
class 田中CurryMaker {
  String make(
      String carrotId, String potatoId, String onionId, String meatId
  ) {

     // 1. 野菜を切って下準備
    String vegetableId = this.下準備工程.する(carrotId, potatoId, onionId); //this.はコンストラクタで差し込まれてるイメージです

    // 2. 鍋に投入して、煮込む
    鍋 pot= 鍋.取り出す().投入(meatId, vegetableId);
    this.煮込み工程.煮こむ(pot);
   
    // 3. カレー粉投入して煮込む
    pot.投入(カレー粉.取り出す());
    this.上げ煮込み工程.煮込む(pot);

    return pot;
  }
}
```

佐藤

```java

class 佐藤CurryMaker {
  String make(
      String carrotId, String potatoId, String onionId, String meatId
  ) {

    // 1. 野菜を切って下準備
    String vegetableId = this.下準備工程.する(carrotId, potatoId, onionId);

    // 2. 鍋に投入して、煮込む
    鍋 pot= 鍋.取り出す().投入(meatId, vegetableId);
    this.炒め工程.炒める(pot);
    this.煮込み工程.煮こむ(pot); 

    // 3. カレー粉投入して煮込む
    pot.投入(カレー粉.取り出す());
    this.仕上げ煮込み工程.煮込む(pot);

    return pot;
  }
}
```

中村

```java

// 禁断の中村家 !!
class 中村CurryMaker {
  String make(
      String carrotId, String potatoId, String onionId, String meatId
  ) {

    // 1. 野菜を切って下準備
    String vegetableId = this.下準備工程.する(carrotId, potatoId, onionId);

    // 2. 鍋に投入
    鍋 pot= 鍋.取り出す().投入(meatId, vegetableId);

    // 3. カレー粉投入して煮込む
    pot.投入(カレー粉.取り出す());
    this.仕上げ煮込み工程.煮込む(pot);

    return pot;
  }
}
```

オブジェクト（クラス）

```java

class 鍋{}
class 下準備工程 {} 
class 煮込み工程{}
class カレー粉工程{}
class 仕上げ煮込み工程 {}

// ↑は、異存もなく独立したオブジェクトで、テストの時もその機能に集中できます。
```

少しかっこつけて、`鍋`というオブジェクトオブジェクトしてるものも作ってみました。

ですが、基本的には、独立した"料理の工程"を、そのままクラスに分割をしました。
禁断の中村家も、歪なく記述されていますね。

「下準備工程や各種工程は、interfaceの方が、、、野菜も、」等、色々クラス設計で思いつくこともあるでしょう。
今は、そこではなく「なぜ初級と変わったのか」に注目してもらえると良いかもしれません。

## 初級と比べてみる

どちらも流れ上は自然にクラスを導入しましたが、異なる結果になりました。

**初級++**

* 処理を記述して、処理の共通化の目的で、クラスを導入した。
* 処理のパターンが増えるたびに歪になった。 

**中級入門**

* 仕様を記述して、仕様をコードに落とし込むために、クラスを導入した。
* ある程度のレシピを書いても歪にはならない。

# オブジェクト指向中級 == オブジェクト指向分析/設計入門

クラスや継承のコードを学び、デザインパターンのコードを学び、その先のコードを探しに来たみなさん。
あらためて、こんにちは。
その先は、コードだけではたどり着くのが難しいのです。

"仕様を言葉で整理しなおす"  "仕様をコードに記述する" 
とは、実はオブジェクト指向の分析と設計のプロセスを踏んでいます。

分析（と設計）ときくと、所謂、上流工程の話と受け取ってしまうことがあります。
ですが、洗練されたコードを書く。その願いを叶える長い旅路の次のステップは、ここにあります。

### !注意!

本来、オブジェクト指向分析では、分析段階である程度オブジェクトを導出します。
設計段階では、導出したオブジェクトを組み合わせながら、機能と処理のバランスを取ります。
今回は意図的にオブジェクトの導出を省いてるので、厳密的なプロセスとは異なります。

小難しい話にならないように、コードを記述していく上で、自然な流れとしてクラスを導出しました。
また、今回あえてinterfaceや継承は導入しませんでした。それらを使うことがオブジェクト指向の目的ではないと伝わればと。

## 洗練されたコードは、洗練された仕様に宿る

クラスはなぜ歪になってしまうのか？
それは、オブジェクト指向プログラミング能力の問題、ではないのです。

歪になっているのは、何か？
それは、クラスではなく、"表現したいモノ"そのものが歪んでいるのです。

## 教えてくれない。

デザインパターンやSOLID原則は、そのクラス構造が適切であるかの判断は出来ます。
しかし、クラスで表現したいモノが適切かを判断するのは難しいのです。

オブジェクト指向とは、オブジェクトの相互作用によって達成されます。
相互作用の構造的正しさの判断は可能です。それによりオブジェクトは洗練されていきます。

しかし、相互作用で"表現したいモノ"そのものにについて、それらが述べることはないのです。

## "表現したいモノ"は何か == 分析

分析って本当にいるのかな？と感じますよね。
処理を記述して、似たものを共通化していけば、同じになるのでは。
今回だって、リファクタリングを繰り返せば、いつか同じになるのでは。

だいたいあってるが、だいたい間違っています。

初級++は、リファクタを繰り返すと、中級に変わっていく可能性はあります。
ですが、かなりの大規模なリファクタリングが必要になります。

クラスは、表現したいモノを写した鏡です。
コードが悪いという視点から、クラス(==表現したいモノ)まで視点を広げる必要があります。
まず、それが難しい。

気づいても、修正には相当な勇気が必要になります。
下手に変えると、他のコードから浮いてしまう。やりすぎなのかやりすぎじゃないのか。
迷いの連続です。

分析とは、表現したいモノは何なのか？と問う作業そのものです。
迷いの中で何が正しいのかと問いかける作業そのものだったりします。

## つまらない話はグダグダ長いので

だらだらと話がダレてきたので今回はここで終わりましょう。

コードを流し見して、そんな風にまとめたりするんだ。とか、当然じゃん。とか感じてくれたら幸いです。

近年ドメイン駆動設計によって、この辺りも再フォーカスされましたが、ドメイン駆動はなかなかなかです。
背景にオブジェクト指向分析/設計があると覚えておくと、理解の助けになるかもしれません。
そして、オブジェクト指向分析/設計と名のついた本に手を伸ばそうかな～と思うきっかけになって頂けたら幸いです。