小菜成长记(五)--观察者设计模式 Vs 事件委托

本文通过一个具体的例子介绍了观察者模式的实现方式,并分析了其优缺点。此外,还提出了一种改进方案——事件委托,以解决传统观察者模式中的一些局限性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写一个观察者模式程序:

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直播,继续工作!");
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值