观察者模式-----设计模式与代码的结构特性

观察者模式-----设计模式与代码的结构特性

什么是OBSERVER模式(观察者模式)

Observer模式描述了对相见的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。这一模式的关键对象是目标(subject)和观察者(observer)。一个目标可以有任意数目的依赖它的观察者。一旦目标的状态发生改变,所有的观察者都得到通知。作为对这个通知的相应,每个观察者豆浆查询目标以使其状态与目标的状态同步。这种交互也称为发布--订阅。目标是通知的发布者。它发出通知时并不需要知道谁是它的观察者。可以有任意数目的观察者订阅并接收通知。


意图:

将一个系统分割成一系列相互协作的类有一个常见的副作用:需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,因为这样降低了他们的可重用性。因此定义这样一种一对多的依赖关系,使得当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。


别名:

依赖(Dependents),发布---订阅(Publish-Subscribe)


参与者:

  • Subject(目标)

    • 目标知道它的观察者。可以有任意多个观察者观察同一个目标
    • 提供注册和删除观察者对象的接口
  • Observer(观察者)

    • 为那些在目标发生改变时需获得通知的对象定义一个更新接口
  • ConcreteSubject(具体目标)

    • 将有关状态存入各ConcreteObserver对象
    • 当它的状态发生改变时,向它的各个观察者发出通知
  • ConcreteObserver(具体观察者)

    • 维护一个指向ConcreteSubject对象的引用

    • 存储有关状态,这些状态应与目标的状态保持一致

    • 实现Observer的更新接口以使自身状态与目标的状态保持一致


协作:

  • 当ConcreteSubject发生任何坑你导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者

  • 在得到一个具体目标的改变通知后,ConcreteObserver对象可向目标对象查询信息


适用性:

在以下任意情况下可以使用观察者模式:

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用

  • 当对一个对象的改变需啊哟同时改变其他对象,而不知道具体有多少对象有待改变

  • 当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,你不希望这些对象是紧密耦合的




OBSERVER模式的优缺点

Observer模式允许你独立的改变目标和观察者,你可以单独复用目标对象而无需同时复用其观察者,反之亦然。它也可以使你可以在不改动目标和其他的观察者的前提下增加观察者。下面是观察者模式的其他一些优缺点:

目标和观察者之间的抽象耦合

一个目标所知道的仅仅是它有一系列观察者,每个都符合抽象的Observer类的简单接口。目标不知道任何一个观察者属于哪一个具体的类,这样目标和观察者之间的耦合是抽象的和最小的

因为目标和观察者不是紧密耦合的,它们可以属于一个系统中的不同抽象层次。。一个处于较低层次的目标对象可与一个处于较高层次的观察者通信并通知它,这样就保持了系统层次的完整性

支持广播通信

不像通常的请求,目标发送的通知不需指定它的接收者。通知被自动广播给所有已向该目标对象登记的有关对象。目标对象并不关心到底有多少对象对自己感兴趣;他唯一的责任就是通知它的各观察者。这给了你在任何时刻增加和删除观察者的自由。处理还是忽略一个通知取决于观察者

意外的更新

因为一个观察者并不知道其他观察者的存在,它可能对改变目标的最终代价一无所知。在目标上一个看似无害的操作可能会引起一系列对观察者以及依赖于这些观察者的那些对象的更新。此外,如果依赖准则的定义或维护不当,常常会引起错误的更新,这种错误通常很难捕捉

简单的更新协议不提供具体细节说明目标中什么被改变了,这是的上述问题更加严重。如果没有其他协议帮助观察者发现什么发生了改变,它们可能会被迫尽力减少改变




代码实现步骤

  1. 构造一个主题Subject或者是一个被观察者Observeable,这是一个接口或者是抽象类

      public interface Subject {
       //注册观察者
       void registerObserver(Observer observe);
       //解除绑定观察者
       void unRegisterObserver(Observer observe);
       //更新数据
       void notifyObservers();
     }
  2. 构建一个被观察者实现该主题接口如本例的 DevelopmentProgressData.class,这里是进度信息数据

    在registerObserver(Observer o)方法中将观察者添加到注册列表中

    在unRegisterObserve(Observer o)删除观察者

    public class DevelopmentProgressData implements Subject {
       private ArrayList arrayObserve;
    
       private int completeProgress;//完成进度
       private int updateProgress;//更新进度
    
       public DevelopmentProgressData() {
           arrayObserve = new ArrayList();
       }
     @Override
       public void registerObserver(Observer observer) {
           //将观察者添加到列表中
           arrayObserve.add(observer);
       }
    
       @Override
       public void unRegisterObserver(Observer observer) {
           int i = arrayObserve.indexOf(observer);
           if (i >= 0) {
               //将观察者从列表中解除
               arrayObserve.remove(i);
           }
    
       }
       //通知所以观察者数据更新了
       @Override
       public void notifyObservers() {
    
           for (int i = 0; i < arrayObserve.size(); i++) {
               Observer o = (Observer) arrayObserve.get(i);
               o.update(completeProgress, updateProgress);
           }
       }
    }
  3. 构建一个观察者接口Observer

     public interface Observer {
        //更新数据
        void update(int completeProgress, int updateProgress);
     }
  4. 构建一个展示数据的接口(可忽略)

    有展示数据的方法,观察者要实现这个方法 查看本例的 DisplaySchedule

    public interface DisplaySchedule {
       void display();
    }
  5. 定义观察者(模拟该类就是产品经理观察者),需实现接口Observes、DisplaySchedule(可忽略)

    将主题Subject设置为观察者的属性,并将其作为观察者的构造函数如 ProductManagerObserver.class,调用 developmentProgressSubject.registerObserver(this),将观察者注册到观察列表中

    public class ProductManagerObserver implements Observer, DisplaySchedule {
    
        private int completeProgress;//完成进度
        private int updateProgress;//更新进度
        //将主题当成观察者的属性
        private Subject developmentProgressSubject;
    
        public ProductManagerObserver(Subject developmentProgressSubject) {
            this.developmentProgressSubject = developmentProgressSubject;
            //注册该观察者
            developmentProgressSubject.registerObserver(this);
        }
    
        @Override
        public void display() {
            System.out.println("产品经理管理者显示当前数据 完成进度为: " + completeProgress + "更新修改进度为:" + updateProgress);
        }
    
        @Override
        public void update(int completeProgress, int updateProgress) {
            this.completeProgress = completeProgress;
            this.updateProgress = updateProgress;
            display();
        }
    }
  6. 测试

    RunTest.class

    public class RunTest {
    
        public static void main(String[] args) {
    
            DevelopmentProgressData developmentProgressData = new DevelopmentProgressData();
            ProductManagerObserver productManagerObserver = new ProductManagerObserver(developmentProgressData);
            ProjectManagerObserver projectManagerObserver = new ProjectManagerObserver(developmentProgressData);
            developmentProgressData.setCurrentData(34, 45);
            //当项目经理出差了,不观察项目进度了就取消订阅了
            developmentProgressData.unRegisterObserver(projectManagerObserver);
            //当前只有产品经理获取到数据
            developmentProgressData.setCurrentData(46, 90);
        }
    }
  7. 输出结果

    C:\Java\jdk1.8.0_161\bin\...
    产品经理管理者显示当前数据 完成进度为: 34更新修改进度为:45
    项目管理真显示当前数据完成进度为: 34更新修改进度为:45
    产品经理管理者显示当前数据 完成进度为: 46更新修改进度为:90
    
    Process finished with exit code 0

参考资料

猜你喜欢

转载自www.cnblogs.com/zhouyuxi/p/12006646.html