设计模式之观察者模式的Java实现

什么是观察者模式

摘自百度的解释

观察者(Observer)模式又名发布-订阅(Publish/Subscribe)模式。GOF给观察者模式如下定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
这里写图片描述

观察者模式的优缺点

  • 观察者模式的优点:
    1.观察者模式实现了观察者和目标之间的耦合
    2.观察者模式实现了动态联动
    3.观察者模式支持广播通信
  • 观察者模式的缺点:
    1.可能会引起无谓的操作
    比如说你想推送的消息,只给某个观察者,但此刻忘了删除其他的观察者,一经推送,其他观察者都收到了,这样就会产生比较麻烦的事情。

代码实现

经典的观察者模型
//Subject目标类
public class Subject{
    //维护观察者
    private List<Observer> observers = new ArrayList<Observer>();

    //对观察者进行添加
    public void attech(Observer observer){
        observers.add(observer);
    }

    //对观察者进行删除
    public void detech(Observer observer){
        observers.add(observer);
    }

    //对每个观察者进行广播
    protected void notifyObservers(){
        for(Observer observer:observers){
            observer.update(this);
        }
    }
}

//Observer观察者接口
public interface Observer{
    public void update(Subject subject);
}

//Subject实现类,负责设置属性状态
public class ConcreteSubject extends Subject{
    private String content;

    public void setContent(String content){
        this.content = content;
        //当设置状态了,就需要对每个观察者进行广播,让他们及时更新消息
        this.notifyObservers();
    }
    public String getContent(){
        return content;
    }
}

//观察者实现类
public class ConcreteObserver implements Observer{
    //观察者的状态,负责接收subject目标发过来的状态
    private String observerState;

    //对update()进行实现
    public void update(Subject subject){
    }
}
现在将观察者放在一个场景中

比如说,我的女朋友和老妈很喜欢买衣服(不经意间暴露了嘿嘿…),然而她们在上网买衣服时觉得很麻烦,必须要花费很长时间来进行挑选,我做了一个软件把上网比较受欢迎的衣服消息同时推送给她们,这样就比较方便了。
下面我们来进行代码的实现吧!!
by the way现在我用的是观察者中的拉模型实现的,稍后我会介绍观察者模式中推模型和拉模型的区别

//目标对象类,负责维护女朋友和老妈这两个观察者
public class BuySubject{
    private List<Observer> observers = new ArrayList<Observer>();

    public void attech(Observer observer){
        observers.add(observer);
    }

    public void detech(Observer observer){
        observers.remove(observer);
    }

    //进行广播通知,非子类是不能得到该方法的
    protected void notifyObservers(){
        for(Observer observer:observers){
            observer.update(this);
        }
    }
}

//Observer观察者接口
public interface Observer{
    //将整个目标对象发给观察者,需要什么取什么(想拉什么拉什么),所以就是拉模型了
    public void update(BuySubject subject);
}

//subject目标对象的实现
public class ConcreteBuySubject extends BuySubject{
    //将衣服的信息放在此处,等会推送给观察者
    private String clothesContent;

    public void setClothesContent(String clothesContent){
        this.clothesContent = clothesContent;
        this.notifyObservers();
    }

    public String getClothesContent(){
        return clothesContent;
    }
}

//Observer观察者接口的实现
public class ConcreteObserver implements Observer{
    //观察者的名称
    private String observerName;

    //观察者的状态,从subject接收过来的
    private String clothesContent;

    public void update(BuySubject subject){
        clothesContent = ((ConcreteBuySubject)subject).getClothesContent();
        System.out.println(observerName+"收到了"+clothesContent);
    }

    public void setObserverName(String observerName){
        this.observerName = observerName;
    }
    public String getObserverName(){
        return observerName;
    }
}

//测试类
public class Test{
    public static void main(String[] args){
        //1.创建目标对象
        ConcreteBuySubject subject = new ConcreteBuySubject();

        //2.创建观察者
        ConcreteObserver myGirl = new ConcreteObserver();
        myGirl.setObserverName("我的女票");

        ConcreteObserver myMum = new ConcreteObserver();
        myMum.setObserverName("我的老妈");

        //3.注册观察者
        subject.attech(myGirl);
        subject.attech(myMum);

        //4.推送消息
        subject.setClothesContent("爆款长裙,淘宝地址:https://taobao.com/...../");
    }
}   
同样,我们展示一下推模型

推模型就是不管消息你愿不愿意接收,我都发送给你。

//目标对象
public class BuySubject{
    private List<Observer> observers = new ArrayList<Observer>();

    public void attech(Observer observer){
        observers.add(observer);
    }

    public void detech(Observer observer){
        observers.remove(observer);
    }

    //此处加入了一个参数,用来传递想要发送的消息
    public void notifyObservers(String content){
        for(Observer observer:observers){
            observer.update(content);
        }
    }
}

//Observer观察者接口
public interface Observer{
    //接收的不再是对象,而是具体什么类型的消息
    public void update(String content);
}

//目标对象实现类
public class ConcreteBuySubject extends BuySubject{
    private String clothesContent;

    public void setClothesContent(String clothesContent){
        this.clothesContent = clothesContent;
        this.notifyObservers(clothesContent);
    }
}

//Observer实现类
public class ConcreteObserver implements Observer{
    private String observerName;

    private String clothesContent;

    public void update(String content){
        clothesContent = content;
    }

    public String getObserverName() {
        return observerName;
    }
    public void setObserverName(String observerName) {
        this.observerName = observerName;
    }
}

Test类和拉模型是一样的,得到的结果也是相同的,但具体实现的方式是不同的。

在Java中本身也提供了观察者模式的接口,我们只要实现接口,就可以直接使用可以更加方便

//目标对象的具体实现类
public class ConcreteBuySubject extends Observable{
    //推送衣服的内容
    private String content;

    public String getContent(){
        return content;
    }

    public void setContent(String content){
        this.content = content;

        //进行通知前,必不可少的方法
        this.setChanged();

        //主动通知观察者,属于推模型
        this.notifyObservers(content);

        //如果是拉模型,直接把subject传过去
        //this.notifyObservers();
    }
}

//观察者的具体实现
public class ConcreteObserver implements Observer{
    //观察者的名称,老妈,女朋友
    private String observerName;

    //第一个参数是传一个目标的引用过来,是拉模型
    //第二个参数是传一个参数过来,是推模型
    public void update(Observable o,Object arg){
        //推模型
        System.out.println(observerName+"收到了信息,推过来的是"+arg);
        //拉模型
        System.out.println(observerName+"收到了消息,主动到目标去拉,拉过来的是"+((ConcreteBuySubject)o).getContent());
    }
    public String getObserverName() {
        return observerName;
    }

    public void setObserverName(String observerName) {
        this.observerName = observerName;
    }
}
观察者模式的高级实现

现在呢,我的女朋友对我又有了新的要求,她还想买鞋子,想让我把鞋子的信息也推送给她,但我老妈比较节俭,她就不要鞋子了,想省点钱。这个时候就不能把消息一股脑儿的全都推送给她们。需要按需分配消息了,这个时候该怎么实现呢?

//目标对象抽象类,用来管理观察者列表和广播消息
public abstract class BuySubject{
    //用来管理观察者
    private List<Observer> observers = new ArrayList<Observer>();

    public void attech(Observer observer){
        observers.add(observer);
    }

    public void detech(Observer observer){
        observers.remove(observer);
    }

    //用来对观察者进行广播,设为抽象类,具体实现由子类来实现
    public abstract void notifyObservers();
}

//观察者接口,具有更新方法,可以设置观察者名称
public interface Observer{
    public void update(BuySubject subject);

    public void setObserverName(String observerName);

    public String getObserverName();
}

//目标对象的实现类,负责设置推送的消息,实现广播方法
public class ConcreteBuySubject extends BuySubject{
    //设置状态,“衣服” “鞋子”
    private String content;

    public void notifyObservers(){
        //循环观察者
        for(Observer observer:observers){
            if("衣服".equals(this.getContent())){
                if("女朋友".equals(observer.getObserverName())){
                    observer.update(this);
                }else if("老妈".equals(observer.getObserverName())){
                    observer.update(this);
                }
            }

            if("鞋子".equals(this.getContent())){
                if("女朋友".equals(observer.getObserverName())){
                    observer.update(this);
                }
            }
        }
    }
    public String getContnt() {
        return contnt;
    }

    public void setWeatherContnt(String contnt) {
        this.contnt = contnt;
        this.notifyObservers();
    }
}

//实现观察者接口,从目标对象接收要购买衣服鞋子的消息
public class ConcreteObserver implements Observer{
    //观察者的名字
    private String observerName;

    //内容“衣服”“鞋子”
    private String content;

    //设置商品的特点
    private Sting specialThing;

    public void update(BuySubject subject){
        content = ((ConcreteBuySubject)subject).getContent();
        System.out.println(observerName+"收到了"+content"内容的推送,"+specialThing);
    }

    public String getObserverName(){
        return observerName;
    }
    public void setObserverName(String observerName){
        this.observerName = observerName;
    }
    public String getSpecialThing(){
        return specialThing;
    }
    public void setSpecialThing(){
        this.specialThing = specialThing;
    }
}

//测试类
public class Test{
    public static void main(String[] args){
        //1.实现目标对象
        ConcreteBuySubject subject = new ConcreteBuySubject();

        //2.建立观察者
        ConcreteObserver myGirl = new ConcreteObserver();
        myGirl.setObserverName("老妈");
        myGirl.setSpecialThing("碎花长裙,劲爆5折");

        ConcreteObserver myMum = new ConcreteObserver();
        myMum.setObserverName("女朋友");
        myMum.setSpecialThing("碎花长裙,劲爆5折;小牛皮休闲女鞋,一买双第二双半价");

        //3.注册观察者
        subject.attech();
        subject.attech();

        //4.推送消息
        subject.setContent("衣服");
        //subject.setContent("鞋子");
    }
}

观察者模式就简单的介绍完毕了!希望大家都有自己的女朋友,真的给自己老妈和女票做个这样的软件方便她们买买买,剁剁剁~^_^!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值