小菜成長記(五)--觀察者設計模式 Vs 事件委託

寫一個觀察者模式程序:

public class Program {
    public static void main(String[] args) {
        Secretary tongzizhe = new Secretary();
        // 看股票的同事
        Observer tongshi1 = new StockObserver("小君", tongzizhe);
        Observer tongshi2 = new NBAObserver("小海", tongzizhe);

        // 前臺記下了兩位同事
        tongzizhe.attach(tongshi1);
        tongzizhe.attach(tongshi2);
        // 發現老闆回來
        tongzizhe.setAction("老闆回來了");
        // 通知兩個同事
        tongzizhe.notifyObserver();
    }
}

interface Subject {
    void attach(Observer observer);
    void remove(Observer observer);
    void notifyObserver();
}

class Secretary implements Subject{
    // 同事列表
    private List<Observer> observerList = new ArrayList<Observer>();
    private String action;

    // 增加
    public void attach(Observer observer) {
        observerList.add(observer);
    }

    // 移除
    public void remove(Observer observer) {
        observerList.remove(observer);
    }

    // 通知
    public void notifyObserver() {
        for (Observer observer : observerList) {
            observer.update();
        }
    }

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }
}

abstract class Observer {
    protected String name;
    protected Secretary sub;

    public Observer(String name, Secretary sub) {
        this.name = name;
        this.sub = sub;
    }

    public abstract void update();
}

class StockObserver extends Observer{
    public StockObserver(String name, Secretary sub) {
        super(name, sub);
    }

    @Override
    public void update() {
        System.out.println(sub.getAction()+name+"關閉股市行情,繼續工作!");
    }
}

class NBAObserver extends Observer {

    public NBAObserver(String name, Secretary sub) {
        super(name, sub);
    }

    @Override
    public void update() {
        System.out.println(sub.getAction()+name+"關閉NBA直播,繼續工作!");
    }
}

觀察者模式的優缺點

優點

很好地解耦了通知者與觀察者,觀察者不需要了解通知者內部是怎樣實現的,方便於日後代碼的修改,體現了 依賴倒轉的原則。

缺點分析:

分析:

  1. “上面該機的代碼中抽象通知者還是依賴了抽象觀察者,萬一沒有抽象觀察者,那豈不是功能都完成不了啦!
  2. 還有你這上面代碼寫的,所以對象更新的動作都一樣的。萬一我對象更新不一樣呢?比如,看NBA球賽的聽見班主任來了就跑去上廁所,而看漫畫的聽見班主任來了就繼續看書。代碼又應該怎麼寫呢?”小A,揉了揉惺忪的睡眼,疑惑地問道。
  3. 小B說:“我去,我還以爲你睡着了呢!原來你在聽啊!我太高興了。下面我們就利用一種叫做“事件委託”的東東去解決這個問題哈!”
  4. 小A說:“我滴個神,什麼叫事件委託啊?”

解決方法

1.解決方法,使用事件委託

當觀察者不實現Observer的時候,要採用事件委託。
public class Program {
    public static void main(String[] args) {
        Secretary tongzizhe = new Secretary();
        // 看股票的同事
        Observer tongshi1 = new StockObserver("小君", tongzizhe);
        NBAObserver tongshi2 = new NBAObserver("小海", tongzizhe);

        // 前臺記下了兩位同事
        tongzizhe.addListener(tongshi1, "update");
        tongzizhe.addListener(tongshi2, "closeNBA");
        // 發現老闆回來
        tongzizhe.setAction("老闆回來了");
        // 通知兩個同事
        tongzizhe.notifyObserver();
    }
}

class Event{
    // 要執行方法的對象
    private Object object;
    // 要執行方法的名稱
    private String methodName;
    // 要執行方法的參數
    private Object[] params;
    // 要執行方法的參數類型
    private Class[] paramTypes;

    public Event(){}

    public Event(Object object, String methodName,Object...args){
        this.object = object;
        this.methodName = methodName;
        this.params = args;
        contractParamTypes(this.params);
    }

    //根據參數數組生成參數類型數組
    private void contractParamTypes(Object[] params){
        this.paramTypes = new Class[params.length];
        for(int i = 0; i < params.length; i++){
            this.paramTypes[i] = params[i].getClass();
        }
    }

    public Object getObject() {
        return object;
    }

    /**
     * 根據該對象的方法名,方法參數,利用反射機制,執行該方法
     * @throws Exception
     */
    public void invoke() throws Exception{
        Method method = object.getClass().getMethod(this.getMethodName(), this.getParamTypes());
        if(null == method){
            return;
        }
        method.invoke(this.getObject(), this.getParams());
    }

    public void setObject(Object object) {
        this.object = object;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Object[] getParams() {
        return params;
    }

    public void setParams(Object[] params) {
        this.params = params;
    }

    public Class[] getParamTypes() {
        return paramTypes;
    }

    public void setParamTypes(Class[] paramTypes) {
        this.paramTypes = paramTypes;
    }
}

class EventHandler {
    private List<Event> objects;

    public EventHandler(){
        objects = new ArrayList<>();
    }

    public void addEvent(Object object, String methodName,Object...args){
        objects.add(new Event(object, methodName, args));
    }

    //通知所有的對象執行指定的事件
    public void notifyX() throws Exception{
        for(Event e : objects){
            e.invoke();
        }
    }
}

abstract class Subject {
    private EventHandler eventHandler = new EventHandler();
    private String action;

    public EventHandler getEventHandler() {
        return eventHandler;
    }

    public void setEventHandler(EventHandler eventHandler) {
        this.eventHandler = eventHandler;
    }

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }


    abstract void addListener(Object object, String methodName,
                                     Object... args);

    abstract void notifyObserver();
}

class Secretary extends Subject{
    @Override
    void addListener(Object object, String methodName, Object... args) {
        EventHandler handler = this.getEventHandler();
        handler.addEvent(object, methodName, args);
    }

    @Override
    void notifyObserver() {
        try {
            this.getEventHandler().notifyX();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

abstract class Observer {
    protected String name;
    protected Subject sub;

    public Observer(String name, Subject sub) {
        this.name = name;
        this.sub = sub;
    }

    public abstract void update();
}

class StockObserver extends Observer{
    public StockObserver(String name, Subject sub) {
        super(name, sub);
    }

    @Override
    public void update() {
        System.out.println(sub.getAction()+name+"關閉股市行情,繼續工作!");
    }
}

class NBAObserver{
    protected String name;
    protected Subject sub;

    public NBAObserver(String name, Subject sub) {
        this.name = name;
        this.sub = sub;
    }

    public void closeNBA() {
        System.out.println(sub.getAction()+name+"關閉NBA直播,繼續工作!");
    }
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章