にゃんこで分かるObserverパターン 後編

#概要
[前回](https://qiita.com/lookman/items/0cfd05702678738ab336)は、飼いねこと野良ねこの2匹を用いて、Observer パターンの構造を説明しました。今回はObserver.update 関数を中心に、にゃんこがごはんだけでなく他のものをねだるようになります。[前回](https://qiita.com/lookman/items/0cfd05702678738ab336)の内容を前提として解説いたしますので、先にそちらをご覧ください。

![IMG_0756.JPG](https://qiita-image-store.s3.amazonaws.com/0/231330/d95ac2ae-121c-1c2f-ecb6-5cc03b43b58b.jpeg)
*（ちょっとボケてますが、庭をのぞきこむ実家のにゃんこ）*

#登場するにゃんこ

**飼い猫のタマ**
タマは、マンションの3階で暮らしています。飼い主は一人暮らしです。

![cat_matatabi.png](https://qiita-image-store.s3.amazonaws.com/0/231330/0a7c2ef0-3374-46fd-d149-7aca205dcb3d.png)

**飼い猫のモモ**
最近、タマと同じ家に住むようになりました。

![cat_scottish_fold.png](https://qiita-image-store.s3.amazonaws.com/0/231330/dfc2de99-27e8-cca7-869e-6ee532ce3e69.png)

#ごはんだけでは満足できないタマ
タマが飼い主におねだりするのは、ごはんだけではありません。遊んでほしかったりマタタビが気になったりします。
飼い主にどのお願いをしているかを伝える方法は、おおまかに2つあります。引数を介して渡す**Push型**と、引数を介さないで（その他の方法を用いて）渡す**Pull型**です。
[前回](https://qiita.com/lookman/items/0cfd05702678738ab336)のコードは引数がなかったため、Pull型に分類されます。引数を受け取る必要がない処理の場合はPull型を用いるといいでしょう。もしPull型で必要な情報がある場合は、Observer クラスが集めたり、自身が知っているものを用いたりします。
一方、Push型では引数に、文字列や数値、Event クラス（後述）などを渡します。

#飼い主にお願いを伝える
まずは、様々なおねだりをできるようにするために「お願い」をクラスにします。

``` Request.java
public abstract class Request{// Event クラス
    public abstract void words();
}
```

``` Food.java
public class Food extends Request{// Event クラス
    @Overide
    public void words(){
        System.out.println("にゃー（おなかすいた）");
    }
}
```

``` Playing.java
public class Playing extends Request{// Event クラス
    @Overide
    public void words(){
        System.out.println("にゃー（ひまー）");
    }
}
```

``` Matatabi.java
public class Matatabi extends Request{// Event クラス
    @Overide
    public void words(){
        System.out.println("にゃー（マタタビほしい！）");
    }
}
```

![uml4.png](https://qiita-image-store.s3.amazonaws.com/0/231330/20bab2f1-2331-a3ad-1edb-dd51b6b80d6a.png)

## Event クラスを渡す
次の例はPush型で、Request クラス（＝Event クラス) を引数にしたコードです。

```Cat.java
public class Cat{// Subject クラス
    private Human human;
    
    public void setHuman(Human human){// setObserver()
        this.human = human;
    }

    public void hungry(){// notifyObservers()
        this.human.called(new Food());
    }

    public void killTime(){// notifyObservers()
        this.human.called(new Playing());
    }

    public void wantMatatabi(){// notifyObservers()
        this.human.called(new Matatabi());
    }
}
```

```Human.java
public class Human{// Observer クラス
    public void called(Request request){// notify() or update()
        request.words();

        String className = request.getClass().getName();
        if(className.equals(Food.class.getName())){
            System.out.println("カリカリをあげる");

        } else if(className.equals(killTime.class.getName())) {
            System.out.println("もう、しょうがないなー（ねこじゃらしフリフリ）");

        } else if(className.equals(Matatabi.class.getName())) {
            System.out.println("マタタビをあげる");
        }
    }
}
```

```Main.java
    public static void main(String[] args) {
        Cat tama = new Cat();
        Human master = new Human();
        tama.setHuman(master);

        tama.hungry();
        tama.killTime();
        tama.wantMatatabi();
    }
```

```
にゃー（おなかすいた）
カリカリをあげる
にゃー（ひまー）
もう、しょうがないなー（ねこじゃらしフリフリ）
にゃー（マタタビほしい！）
マタタビをあげる
```

## Subject クラス自身（this）を渡す

よく渡す値として、呼び出し元のSubject クラス（＝Cat クラス）自身もあります。Observer クラス（＝Human クラス）が複数のSubject クラスから呼び出される場合、呼び出し元が分かるため便利です。

```Cat.java
public class Cat{// Subject クラス
    private Human human;
    private Request request;
    public final String name;
    
    public Cat(String name){
        this.name = name;
    }

    public void setHuman(Human human){// setObserver()
        this.human = human;
    }

    public void hungry(){// notifyObservers()
        request = new Food();
        this.human.called(this);
    }

    public void killTime(){// notifyObservers()
        request = new Playing();
        this.human.called(this);
    }

    public void wantMatatabi(){// notifyObservers()
        request = new Matatabi();
        this.human.called(this);
    }

    public Request getRequest(){
        return request;
    }
}
```

```Human.java
public class Human{// Observer クラス
    public void called(Cat cat){// notify() or update()
        cat.getRequest().words();

        String className = cat.getRequest().getClass().getName();
        if(className.equals(Food.class.getName())){
            System.out.println(cat.name + "にカリカリをあげる");

        } else if(className.equals(killTime.class.getName())) {
            System.out.println("もう、しょうがないなー（ねこじゃらしフリフリ）");

        } else if(className.equals(Matatabi.class.getName())) {
            System.out.println(cat.name + "にマタタビをあげる");
        }
    }
}
```

```Main.java
    public static void main(String[] args) {
        Cat tama = new Cat("タマ");
        Cat momo = new Cat("モモ");
        Human master = new Human();
        tama.setHuman(master);
        momo.setHuman(master);

        tama.hungry();
        tama.killTime();
        momo.hungry();
        tama.wantMatatabi();
    }
```

```
にゃー（おなかすいた）
タマにカリカリをあげる
にゃー（ひまー）
もう、しょうがないなー（ねこじゃらしフリフリ）
にゃー（おなかすいた）
モモにカリカリをあげる
にゃー（マタタビほしい！）
タマにマタタビをあげる
```
Java の Observer クラスでは、呼び出し元のSubject クラス（Java内ではObservable クラスという名前）と、Object 全般を引数で受け取れるようになっています。

#おわりに
Push型とPull型のどちらを用いるかは、私もまだはっきりとしたことは言えません（勉強中）。ぜひ参考資料をご覧になってください。

[前回](https://qiita.com/lookman/items/0cfd05702678738ab336)はたくさんの「いいね」をいただけてとても嬉しかったです。ありがとうございます。普段見ている[qiitaランキング](https://qiita.com/takeharu/items/bb154a4bc198fb102ff3)に前回の記事が載っていて、かなり驚きました（思わずスクショを撮りました）。この記事も皆さまのお役に立てば幸いです。

#参考資料
[1][https://qiita.com/varmil/items/8cd8fe9da510e31d940a]
[2][http://d.hatena.ne.jp/backpaper0/20111111/1321012118]
[3][http://apsec99-www.se.cs.titech.ac.jp/local/material/design-patterns/resources/19.html]