zoukankan      html  css  js  c++  java
  • 设计模式实战应用之二:观察者模式

            观察者模式的定义
            观察者模式是应用最普遍的设计模式之一。著名的 MVC 模式就是观察者模式的应用之一。Gof 把观察者模式归类到对象行为型模式,《 设计模式:可复用面向对象软件的基础》对观察者模式做出了明确的定义:“ Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.” 翻译过来就是:“ 定义了一些对象之间的一对多依赖关系,这样子当一个对象的状态发生变化时,所有依赖于这个对象的对象都会得到通知,并被自动更新”。
            why 观察者模式?
            把系统设计成一些互相合作的类有一个常见的弊端:需要维护相关对象之间的一致性。为了维护一致性而使各类紧密耦合,大大降低了模块的可复用性,这是我们不愿意看到的。
            观察者模式的使用场合

    • 当一个抽象模型具有一方依赖于另一方的两方面时,将它们封装在独立的对象中可以让你对它们独立地改变和复用。
    • 当对于一个对象的改变需要同时改变其他对象,而且你不知道有多少对象需要改变。
    • 当一个对象需要通知其他对象,又不能假定其他对象是谁,换句话说,你不希望这些对象紧密地耦合在一起。

            《多线程高效读取缓冲区数据》需求
            本文示例摒弃了那些枯燥无味、与我们项目毫无关联的鸭子啊报社啊葡萄园之类的,同时也因为抄来抄去而被用烂了的无聊话题,采用的是 CSDN 网友项目实战中真实遇到而提出来的一个问题作为案例进行分析。让我们切实感受设计模式带来的好处,领略设计模式的真正的威力,而不只是用来玩理论、侃大山。
            这个是网友 xgPaul 发帖提出的一个讨论。标题是《如何实现多线程高效的读取一块缓冲区中的数据???》帖子链接是: http://bbs.csdn.net/topics/390658695
            帖子正文描述如下:
            一条线程不断的对一块内存缓冲区进行写数据,同时几十条线程(几百个对象)要从该缓冲区中读取数据。这一过程如何实现高效与数据同步。(使用锁同步效率太低)
            《多线程高效读取缓冲区数据》分析
            xgPaul 遇到的这个问题,比较类似于上海抢拍车牌号的场景:一条线程不断地对当前价格进行刷新,同时几十条线程(几百个对象)对当前价格进行读取监控。用观察者模式效率比较好,可以解决由于线程竞争、加锁而带来的效率问题。把读数据的线程归为观察者,主题是缓冲区数据。一旦数据有更新,主题向观察者推送更新数据,这样推数据的做法效率很高。缓冲区做成主题,每个观察者都有一份自己关心的主题数据的本地备份,如果主题没有推数据过来,本地备份就是最新数据。当然,这么干稍耗空间,但是却换得多线程环境中效率上的大幅度提升,这就是所谓的用空间换时间。
            java.lang.ThreadLocal 就是这种原理的一个实现。
            《多线程高效读取缓冲区数据》类设计
            本文重在讲解模式,所以仅以一个 int 类型的数据 onlinePlayersNum 模拟缓冲区数据。两个发布板,一个公开发布板一个内部发布板作为观察者。
            由 BufferData 对象向两个发布板推数据,后者不需要去前者查询数据,只需要查询自己的状态是否改变以决定是否更新发布。具体类图设计如下:
    观察者模式类图
            《多线程高效读取缓冲区数据》时序图
    观察者模式时序图
            《多线程高效读取缓冲区数据》源码实现
            《 设计模式:可复用面向对象软件的基础》的观察者模式中的 Subject 角色,在本文中是为 Subject 接口,源码:

    package com.defonds.buffer;
    
    public interface Subject {
    	public void registerObserver(Observer observer);
    	public void removeObserver(Observer observer);
    	public void notifyObservers();
    }


            《 设计模式:可复用面向对象软件的基础》观察者模式中的 Observer 角色,在本文中是为 Observer 接口,源码:

    package com.defonds.buffer;
    
    public interface Observer {
    	public void update(int onlineNum);
    }


            《 设计模式:可复用面向对象软件的基础》观察者模式中的 ConcreteSubject 角色,在本文中是为 BufferData 类,源码:

    package com.defonds.buffer;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    public class BufferData implements Subject {
    	private int onlinePlayersNum = 0; // store online players num
    	private List<Observer> observers = new ArrayList<Observer>(); // refer to all observers
    	
    	@Override
    	public void registerObserver(Observer observer) {
    		this.observers.add(observer); // add one observer
    		
    	}
    
    	@Override
    	public void removeObserver(Observer observer) {
    		int i = this.observers.indexOf(observer);
    		if (i >= 0) {
    			this.observers.remove(i);
    		}
    
    	}
    
    	@Override
    	public void notifyObservers() {
    		Iterator<Observer> iterator = this.observers.iterator();
    		while (iterator.hasNext()) {
    			iterator.next().update(this.onlinePlayersNum);
    		}
    	}
    
    	public void setOnlinePlayersNum(int onlinePlayersNum) {
    		this.onlinePlayersNum = onlinePlayersNum;
    		this.notifyObservers();
    	}
    	
    	
    
    }


            《 设计模式:可复用面向对象软件的基础》观察者模式中的 ConcreteObserver 角色之一,在本文中是为 PublicDisplay 类,源码:

    package com.defonds.buffer;
    
    public class PublicDisplay extends Thread implements Observer, Display {
    	private int onlineNum;
    	private boolean changed = false;
    
    	@Override
    	public void update(int onlineNum) {
    		this.onlineNum = onlineNum;
    		this.changed = true;
    	}
    	
    	@Override
    	public void display() {
    		System.out.println("The current number of players online is : " + this.onlineNum);
    	}
    
    	@Override
    	public void run() {
    		while (this.changed) {
    			this.display();
    			this.changed = false;
    		}
    	}
    }

            《设计模式:可复用面向对象软件的基础》观察者模式中的 ConcreteObserver 角色之二,在本文中是为 InternalDisplay 类,源码:

    package com.defonds.buffer;
    
    public class InternalDisplay extends Thread implements Observer, Display {
    	private int oldNum = 0;
    	private int onlineNum = 0;
    	private boolean changed = false;
    
    	@Override
    	public void update(int onlineNum) {
    		this.oldNum = this.onlineNum;
    		this.onlineNum = onlineNum;
    		this.changed = true;
    	}
    	
    	@Override
    	public void display() {
    		System.out.println("The current number of players online is : " + this.onlineNum);
    		if(this.onlineNum > this.oldNum) {
    			System.out.println("The number of online upward");
    		} else {
    			System.out.println("The number of online decline");
    		}
    	}
    	
    	@Override
    	public void run() {
    		while (this.changed) {
    			this.display();
    			this.changed = false;
    		}
    	}
    
    }
  • 相关阅读:
    C++中的名字重整技术
    Linux下C++开发常用命令
    《Effective C++(第三版)》 的55条建议
    我也介绍下sizeof与strlen的区别
    POJ
    HDU
    HDU-1754-I Hate It(单点更新+区间查询)
    HDU多校1003-Divide the Stones(构造)
    Just an Old Puzzle(2019多校1007)
    Idiomatic Phrases Game(最短路+注意坑点)
  • 原文地址:https://www.cnblogs.com/fuhaots2009/p/3459172.html
Copyright © 2011-2022 走看看