【设计模式】-观察者模式(Observer)

又叫做发布-订阅模式
定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新

观察者模式中的角色

Subject:抽象主题(抽象被观察者)抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。
ConcreteSubject:具体主题(具体被观察者)该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
Observer:抽象观察者,定义更新接口,使得在得到主题更改通知时更新自己。
ConcreteObject:具体观察者,在得到主题更改通知时更新自身的状态。

观察者模式结构图解

观察者模式结构图

Demo:新闻社 + 新闻社订阅者

//抽象观察者
abstract public class Observer {
    public abstract void update(String msg);
}

//具体观察者 
public class NewsSubUser extends Observer {
    private String username;
    public NewsSubUser(String name){
        this.username = name;
    }
    public void update(String msg) {
        System.out.println("尊敬的["+username+"]用户,您有一条新闻:"+msg);
    }
}

//抽象被观察者
abstract public class Subject {
    //新增订阅者
    public abstract void add(Observer observer);
    //移除订阅者
    public abstract void remove(Observer observer);
    //通知订阅者
    public abstract void notifyUser(String msg);
}

//具体被订阅者(新闻社)
public class NewsOffice extends Subject {
    //存放订阅者
    private List<Observer> list = new ArrayList<Observer>();
    //添加订阅者
    public void add(Observer observer) {
        list.add(observer);
    }
    //移除订阅者
    public void remove(Observer observer) {
        list.remove(observer);
    }
    //通知订阅者
    public void notifyUser(String msg) {
        //遍历订阅者 依次通知
        for(Observer observer : list){
            observer.update(msg);
        }
    }
}

//测试方法
public static void main(String[] args){
    //订阅者
    NewsSubUser user = new NewsSubUser("cllblogs");
    NewsSubUser user2 = new NewsSubUser("cll");
    NewsSubUser user3 = new NewsSubUser("Mr丶C");
    //新闻社
    NewsOffice news = new NewsOffice();
    //添加订阅者
    news.add(user);
    news.add(user2);
    news.add(user3);
    //提示订阅者有新的消息
    news.notifyUser("2018中国进口博览会开幕式");
}

输出打印结果:
尊敬的[cllblogs]用户,您有一条新闻:2018中国进口博览会开幕式
尊敬的[cll]用户,您有一条新闻:2018中国进口博览会开幕式
尊敬的[Mr丶C]用户,您有一条新闻:2018中国进口博览会开幕式

观察者模式优缺点

优点:观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
缺点:这种依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。

事件委托弥补观察者模式的缺点

//定义一个事件类
public 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;
        assembleParamType(this.params);
    }
    //方法执行类
    public void invoke() throws Exception {
        Method method = object.getClass().getMethod(this.methodName,this.paramTypes);
        if(null == method){
            return;
        }
        method.invoke(this.object,this.params);
    }
    //组装参数类型
    private void assembleParamType(Object[] params) {
        this.paramTypes = new Class[params.length];
        for (int i = 0; i < params.length; i++) {
            paramTypes[i] = params[i].getClass();
        }
    }
}

// EventHandler类  Event事件的载体  添加Event  同时提供执行所有Event的方法
public class EventHandler {
    //存储事件容器
    private List<Event> events;
    public EventHandler(){
        events = new ArrayList<Event>();
    }
    //添加对象要执行的事件以及对应的参数
    public void addEvent(Object object,String methodName,Object ... args){
        events.add(new Event(object,methodName,args));
    }
    //通知事件执行指定的方法
    public void notifyM() throws Exception {
        for(Event event : events){
            event.invoke();
        }
    }
}

// 抽象通知类 1.增加监听者   2.通知监听者执行事件
public abstract class Notifier {
    public EventHandler getEventHandler() {
        return eventHandler;
    }
    public void setEventHandler(EventHandler eventHandler) {
        this.eventHandler = eventHandler;
    }
    private EventHandler eventHandler = new EventHandler();
    //增加监听者
    public abstract void addListener(Object object,String methodName,Object ... args);
    //通知监听者执行事件
    public abstract void notifyM();
}

// 具体通知者 继承抽象通知者 并实现其两个抽象方法
public class TTNotifier extends Notifier {
    //添加监听者
    public void addListener(Object object, String methodName, Object... args) {
        System.out.println("添加新的监听者...");
        this.getEventHandler().addEvent(object,methodName,args);
    }
    //通知监听者
    public void notifyM() {
        System.out.println("通知监听者执行事件...");
        try {
            this.getEventHandler().notifyM();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

// 具体的监听者 
public class TTListenerA {
    //用户名
    private String username;
    public TTListenerA(String username){
        this.username = username;
    }
    //订阅新闻
    public void subNews(){
        System.out.println("我订阅了TT新闻...");
    }
    //查看最新新闻
    public void seeNewNews(String news){
        System.out.println("尊敬的["+username+"]用户,您有一条新闻:"+news);
    }
}

// 测试类
public class Test {
    public static void main(String[] args) throws Exception {
        EventHandler eventHandler = new EventHandler();
        TTListenerA a = new TTListenerA("cllblogs");
        TTListenerA b = new TTListenerA("cll");
        TTListenerA c = new TTListenerA("Mr丶C");
        eventHandler.addEvent(a,"seeNewNews","2018中国进口博览会开幕式");
        eventHandler.addEvent(b,"seeNewNews","2018中国进口博览会开幕式");
        eventHandler.addEvent(c,"seeNewNews","2018中国进口博览会开幕式");
        eventHandler.notifyM();
    }

}

控制台打印结果:
尊敬的[cllblogs]用户,您有一条新闻:2018中国进口博览会开幕式
尊敬的[cll]用户,您有一条新闻:2018中国进口博览会开幕式
尊敬的[Mr丶C]用户,您有一条新闻:2018中国进口博览会开幕式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值