Hatena::ブログ(Diary)

裏紙

 | 

2011-11-11

変態で学ぶObserverパターン

| 20:48

こんばんは! 変態アドベントカレンダーの1日目です。


2日で終わるんじゃね?とかそんなアレは無しの方向でどうかひとつ。別に終わっても良いけど。

というわけで今日はTwitterでObserverパターンについてお話が出ましたので、ここでも学ぶ事にします。

まずObserverパターンて何やねんという話です。登場人物は2人居まして、ObserverさんとSubjectさんです。Observerさんは「何か面白いことがあったら私に教えろください」とSubjectさんにお願いします。しばらくSubjectさんはブラブラ過ごすのですが、突然何か面白いことが起こったとします。すると「うはwwwこれObserverさんに教えなきゃwwwwwワロスwwwww」という具合にObserverさんに面白ハプニングを教えてあげます。以上がObserverパターンの説明になります。

さて、このObserverパターンを実際にコードを書きながら体験してみます。次のようなシナリオを考えてみてください。

  • おまわりさんがjkに「最近この辺りに変態が出るので見かけたら通報よろしく」と頼む
  • jkが変態に遭遇する
  • jkがおまわりさんに通報する
  • 変態逮捕

ではまずObserverとSubject、そして発生した出来事を表現するオブジェクトの基底クラスやインターフェースを作成しましょう。

package hentai.advent.calendar;

public interface Observer {

    void notify(Event event);

}
package hentai.advent.calendar;

import java.util.concurrent.CopyOnWriteArrayList;

public class Subject {

    private CopyOnWriteArrayList<Observer> observers = new CopyOnWriteArrayList<>();

    protected void notifyObservers(Event event) {
        for (Observer o : observers) {
            o.notify(event);
        }
    }

    public void addObserver(Observer o) {
        observers.add(o);
    }

    public void deleteObserver(Observer o) {
        observers.remove(o);
    }

}
package hentai.advent.calendar;

public abstract class Event {

    private final Object source;

    public Event(Object source) {
        this.source = source;
    }

    public Object getSource() {
        return source;
    }

}

次におまわりさん(Observer)、jk(Subject)、変態出没(Event)を作成します。

package hentai.advent.calendar;

/**
 * おまわりさん
 *
 */
public class OmawaListener implements Observer {

    @Override
    public void notify(Event event) {
        System.out.printf("おまわりさん<%sから通報ktkr%n", event.getSource());
        if (event instanceof HentaEvent) {
            System.out.println("変態<タイ━━━━||Φ|(|゚|∀|゚|)|Φ||━━━━ホ!!");
        }
    }

}
package hentai.advent.calendar;

/**
 * jk
 *
 */
public class JK extends Subject {

    public void hentaiShutsubotsu() {
        System.out.println("jk<キャー!!ヘンタイー!!");
        HentaEvent event = new HentaEvent(this);
        notifyObservers(event);
    }

    @Override
    public String toString() {
        return "jk";
    }

}
package hentai.advent.calendar;

/**
 * 変態出没
 *
 */
public class HentaEvent extends Event {

    public HentaEvent(Object source) {
        super(source);
    }

}

最後に先ほどのシナリオをシミュレートするコードを書きます。

package hentai.advent.calendar;

import org.junit.Test;

public class HentaiTest {

    @Test
    public void testHentai() throws Exception {
        JK jk = new JK();
        OmawaListener omawarisan = new OmawaListener();

        //おまわりさんが変態見たら通報してねと頼む
        jk.addObserver(omawarisan);

        //変 態 出 没
        jk.hentaiShutsubotsu();
    }

}

実行結果は次の通り。

jk<キャー!!ヘンタイー!!
おまわりさん<jkから通報ktkr
変態<タイ━━━━||Φ|(|゚|∀|゚|)|Φ||━━━━ホ!!

見事、変態は逮捕されました。

ちなみにJavaSEではObserverパターンをサポートする仕組みとして次のクラス(インターフェース)が用意されています。

  • java.util.Observer
  • java.util.Observable

Observableは最初の説明でいうSubjectに当たります。

また、イベントの基底クラスとして

  • java.util.EventObject

というクラスも用意されています。

これらを使って先ほどのコードを書き直すと次のようになります。

package hentai.advent.calendar.java.util;

import java.util.Observable;
import java.util.Observer;

/**
 * おまわりさん
 *
 */
public class OmawaListener implements Observer {

    @Override
    public void update(Observable o, Object event) {
        System.out.printf("おまわりさん<%sから通報ktkr%n", o);
        if (event instanceof HentaEvent) {
            System.out.println("変態<タイ━━━━||Φ|(|゚|∀|゚|)|Φ||━━━━ホ!!");
        }
    }

}
package hentai.advent.calendar.java.util;

import java.util.Observable;

/**
 * jk
 *
 */
public class JK extends Observable {

    public void hentaiShutsubotsu() {
        System.out.println("jk<キャー!!ヘンタイー!!");
        HentaEvent event = new HentaEvent(this);
        setChanged();
        notifyObservers(event);
    }

    @Override
    public String toString() {
        return "jk";
    }
}
package hentai.advent.calendar.java.util;

import java.util.EventObject;

/**
 * 変態出没
 *
 */
public class HentaEvent extends EventObject {

    public HentaEvent(Object source) {
        super(source);
    }

}

まとめ。

  • 他人に害を与えるような変態イベントを発火させると現代社会に組込まれたObserverパターンで逮捕エンドになるので変態はTPOを守って楽しんでください

……なんて酷いエントリだ

今日のコード(・∀・)つ


追記

yukungyukung 2011/11/11 23:14 クラス名が秀逸ですw

backpaper0backpaper0 2011/11/11 23:22 そこに気付いて貰えて何よりですwww

ぼくぼく 2013/02/14 03:54 随分昔のカレンダーですが、
今日たまたま見つけて感動を覚えました。
がんばってください応援しています。

 |