模式----观察者模式

定义对象间的一种一对多的依赖关系

观察者模式的结构中包括四种角色:

主题(Subject):主题是一个接口,该接口规定了具体主题需要实现的方法
观察者(Observer):观察者是一个接口,该接口规定了具体观察者用来更新数据的方法。
具体主题(ConcreteSubject):具体主题是实现主题接口类的一个实例,该实例包含有可以经常发生变化的数据。具体主题使用一个集合,比如ArrayList,存放观察者的引用,以便数据变化时通知具体的观察者。
具体观察者(Concrete Observer):具体观察者是实现观察者接口的一个实例。具体观察者包含有可以存放具体主题引用的主题接口变量,以便具体观察者让具体主题将自己添加到具体主题的集合中,使自己成为它的观察者,或让这个具体的主题将自己从具体的主题中的观察者列表中删除,使自己不再是它的观察者。

例题:有一个大学毕业生和一个海归留学者都希望能及时知道“求职中心”最新的职业需求信息。

主题(Subject)
package com.subject;

import com.observer.IObserver;

public interface ISubject {
    
    public void addObserver(IObserver o);
    public void deleteObserver(IObserver o);
    public void notifyObservers();
    
}
具体主题(ConcreteSubject)
package com.subject;

import java.util.ArrayList;
import java.util.List;

import com.observer.IObserver;

/**
 * 求职中心,即观察者模式中的:具体主题
 * */
public class SeekJobCenterImpl implements ISubject {
    
    //用于存储:求职信息
    private String msg;
    
    //用于表示求职信息内容是否发生变化,如果变化则通知所有求职者
    private boolean changedFlag;
    
    //用于存储所有求职者(观察者)
    private List<IObserver> observersList;
    
    public SeekJobCenterImpl(){
        this.observersList = new ArrayList<IObserver>();
        this.msg = "";
        this.changedFlag = false;
    }
    
    //向求职者(观察者)列表中添加一个具体的求职者(观察者)
    public void addObserver(IObserver o) {
        if(!this.observersList.contains(o)){
            this.observersList.add(o);
        }

    }

    //从求职者(观察者)列表中删除一个具体的求职者(观察者)
    public void deleteObserver(IObserver o) {
        if(this.observersList.contains(o)){
            this.observersList.remove(o);
        }

    }

    //当数据发生变化时,为所有观察者更新数据信息
    public void notifyObservers() {
        if(this.changedFlag){
            if(this.observersList != null && this.observersList.size() > 0){
                for(int i=0; i<this.observersList.size(); i++){
                    IObserver observer = this.observersList.get(i);
                    //调用求职者(观察者)更新数据的方法为其更新数据
                    observer.hearTelephone(this.msg);
                }
                //所有求职者(观察者)数据更新完毕后,将标志位changedFlag设置为false,表示没有新数据需要更新
                this.changedFlag = false;
            }
        }

    }

    //求职中心(具体主题)设置发布求职信息(数据)使用的方法
    public void setJobInfo(String msg){
        
        if(msg  != null && !msg.trim().equals("")){
            if(this.msg.equals(msg)){
                this.changedFlag = false;
            }else{
                this.msg = msg;
                this.changedFlag = true;
            }
        }

    }
}
观察者(Observer)
package com.observer;

public interface IObserver {
    public void hearTelephone(String msg);
}
具体观察者(Concrete Observer)此处以海归为例

package com.observer;

import java.io.FileWriter;
import java.io.IOException;

import com.subject.ISubject;

public class HaiGuiImpl implements IObserver {
    
    //用于存放具体主题
    private ISubject subject;
    
    public HaiGuiImpl(ISubject subject){
        this.subject = subject;
        //在创建具体求职者(观察者)时,将自己(观察者)加入到具体主题中的观察者列表中
        this.subject.addObserver(this);
    }
    
    //求职者(观察者)用于更新数据的方法
    public void hearTelephone(String msg) {
        //使用的IO流,用于向文本文件中写入更新的数据
        FileWriter fw = null;
        
        
        boolean flag = false;
        try {
            //用于表示求职信息中是否包含:"程序员" 或 "软件"等内容,如果包括,则该观察者将求职信息保存到文件中
            if(msg.contains("程序员") || msg.contains("软件")){
                //第2个参数为true,表示向文件中追加信息,否则将使用新内容覆盖原有内容
                fw = new FileWriter("c:/HaiGui.txt", true);
                //向文件中写入新数据
                fw.write("我收到了一条新的求职信息:" + msg + "\n\r");
                
                System.out.println("我是一个留学生,收到了一条新的求职信息:" + msg);
            }else{
                System.out.println("我是一名留学生,此次没有我需要的求职信息。。。");
            }
            
            
        } catch (IOException e) {
            e.printStackTrace();
        } finally{
            try {
                if(fw != null){
                    fw.close();
                }
                
            } catch (IOException e) {
                e.printStackTrace();
            }
            
        }

    }

}

测试:
package com.test;

import com.observer.HaiGuiImpl;
import com.observer.IObserver;
import com.observer.UniversityStudentImpl;
import com.subject.ISubject;
import com.subject.SeekJobCenterImpl;

public class Application {

    //主程序,用于演示:观察者模式
    public static void main(String[] args) {
        //创建求职中心,即:具体的主题
        SeekJobCenterImpl center = new SeekJobCenterImpl();
        
        /**
         * 创建求职者,即:具体的观察者 
         * universityStudent:代表大学生
         * haiGui:代表留学生
        */
        UniversityStudentImpl universityStudent = new UniversityStudentImpl(center);
        HaiGuiImpl haiGui = new HaiGuiImpl(center);
        
        //求职中心(具体主题)发布新求职信息(数据发生变化)
        center.setJobInfo("腾辉公司需要招聘10名Java程序员。");
        //具体主题通知观察者,更新数据
        center.notifyObservers();
        
        //求职中心(具体主题)发布新求职信息(数据发生变化)
        center.setJobInfo("海景公司需要招聘9名动画设计师。");
        //具体主题通知观察者,更新数据
        center.notifyObservers();
        
        //求职中心(具体主题)发布新求职信息(数据发生变化)
        center.setJobInfo("仁海公司需要招聘9名电工。");
        //具体主题通知观察者,更新数据
        center.notifyObservers();
        
        //求职中心(具体主题)发布了已有的求职信息(即:数据未发生变化)
        center.setJobInfo("仁海公司需要招聘9名电工。");
        //具体主题通知观察者,但观察者不会执行更新数据操作,因为数据没有变化。
        center.notifyObservers();
    }

}













优点:

具体主题和具体观察者是松耦合关系。由于主题(Subject)接口仅仅依赖于观察者(Observer)接口,因此具体主题只是知道它的观察者是实现观察者(Observer)接口的某个类的实例,但不需要知道具体是哪个类。同样,由于观察者仅仅依赖于主题(Subject)接口,因此具体观察者只是知道它依赖的主题是实现主题(subject)接口的某个类的实例,但不需要知道具体是哪个类。


 观察模式满足“开-闭原则”。主题(Subject)接口仅仅依赖于观察者(Observer)接口,这样,我们就可以让创建具体主题的类也仅仅是依赖于观察者(Observer)接口,因此如果增加新的实现观察者(Observer)接口的类,不必修改创建具体主题的类的代码。同样,创建具体观察者的类仅仅依赖于主题(Observer)接口,如果增加新的实现主题(Subject)接口的类,也不必修改创建具体观察者类的代码。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值