设计模式(9)之观察者模式

1. 什么是观察者模式
Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。

2. 观察者模式的结构
这里写图片描述

3. 观察者模式的角色和职责

<1> Subject(被观察者) 被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。
<2> ConcreteSubject 被观察者的具体实现。包含一些基本的属性状态及其他操作。
<3> Observer(观察者) 接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。
<4> ConcreteObserver 观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。

4. 观察者模式的典型应用

  • 侦听事件驱动程序设计中的外部事件
  • 侦听/监视某个对象的状态变化
  • 发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发时,通知邮件列表中的订阅者

下面我们看下Java中的观察者模式的实现,以博主发文章为例。

在这个案例中,显然文章是一个实体,首先建一个类。

//Article.java
public class Article {

    private String title;
    private String content;
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
}

然后是被观察者,博主发完文章会通知各个关注他的人,所以,这里博主是被观察者,其发文章的这件事是被观察的。

java中为我们提供了一个Observable接口, 就是定义了观察者与被观察者之间交互的逻辑。别急,后面我们自己实现一遍,现在我们看看这个接口怎么使用。

//BlogAdministrator.java 

import java.util.Observable;


public class BlogAdministrator extends Observable {

    public void publishBlog(Article article){
        System.out.println("博主:博主发现文章啦,文章标题:"+article.getTitle()+",文章内容:"+article.getContent());
        this.setChanged();//将被观察者设置为change,就是一个标记,这样被观察者就知道观察者发生改变了。
        this.notifyObservers(article);//通知所有的观察者被观察者改变了。这里将博主发布的文章实体传递给观察者,因为观察者光知道被观察者改变了(博主发文章)有啥用呢,当然要拿到文章啊。
    }
}

下面我们定义两个观察者:

//GuanXiObserver.java

import java.util.Observable;
import java.util.Observer;


public class GuanXiObserver implements Observer{

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("-------------guanxi---------------------");
        Article article =  (Article)arg;

        System.out.println("楼主大好人呀,谢谢楼主分享!!!");
        System.out.println("博客标题为:" + article.getTitle());
        System.out.println("博客内容为:" + article.getContent());
    }
}
//TingFengObserver.java

import java.util.Observable;
import java.util.Observer;

public class TingFengObserver implements Observer{

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("-------------tingfeng---------------------");
        Article article =  (Article)arg;

        System.out.println("博主发表了新的文章,快去看吧!");
        System.out.println("博客标题为:" + article.getTitle());
        System.out.println("博客内容为:" + article.getContent());
    }
}

这样,观察者接受到被观察者改变的消息之后,就会自动调用update方法。

//MainClass.java

public class MainClass {
    public static void main(String[] args) {

        BlogAdministrator administrator = new BlogAdministrator();
        //为被观察者添加两个观察者对象
        administrator.addObserver(new GuanXiObserver());
        administrator.addObserver(new TingFengObserver());

        Article article = new Article();
        article.setTitle("论拍照技术的重要性!!!");
        article.setContent("xxxxxxxxxxxxxxxxxxxxxxxxxxxx");

        administrator.publishBlog(article);

    }
}

运行结果为:

博主:博主发现文章啦,文章标题:论拍照技术的重要性!!!,文章内容:xxxxxxxxxxxxxxxxxxxxxxxxxxxx
-------------tingfeng---------------------
博主发表了新的文章,快去看吧!
博客标题为:论拍照技术的重要性!!!
博客内容为:xxxxxxxxxxxxxxxxxxxxxxxxxxxx
-------------guanxi---------------------
楼主大好人呀,谢谢楼主分享!!!
博客标题为:论拍照技术的重要性!!!
博客内容为:xxxxxxxxxxxxxxxxxxxxxxxxxxxx

///

概述
观察者模式(Observer Pattern)是设计模式中行为模式的一种,它解决了上述具有一对多依赖关系的对象的重用问题。此模式的参与者分为两大类,一类是被观察的目标,另一类是观察该目标的观察者们。正因为该模式是基于“一对多”的关系,所以该模式一般是应用于由一个目标对象和N个观察者对象组成(当然也可以扩展为有多个目标对象,但我们现在只讨论前者)的场合。当目标对象的状态发生改变或做出某种行为时,正在观察该目标对象的观察者们将自动地、连锁地作出相应的响应行为。

原理
我们可以把观察目标理解为主动方、发布方、主体等;把观察者理解为被动方、订阅方、观察器等。目标是整个行为链的源头,其它观察者都依赖于它的变化而作出响应。为了实现低耦合,我们不能使用“直接调用”的方式而需要利用“订阅(清单)-通知”的机制去完成设计。通俗地说就是观察者向目标“订阅”它的改变,而目标发生改变后就“通知”所有已经“订阅”了它的改变的观察者,从而执行“订阅”的内容。这种机制的好处在于降低耦合度,分工明确,目标只负责在自身状态发生改变或做出某种行为时向自身的订阅清单发出“通知”,而不是直接调用观察者的行为(方法);观察者只负责向目标“订阅”它的变化,以及定义自身在收到目标“通知”后所需要做出的具体行为(也就是订阅的内容)。就像我们向出版社订阅报刊一样,出版社有新一期报刊发行时并不是直接跟每位订阅者联系,而是“通知”订阅者名单按顺序给每位订阅者发送所订报刊。

实现
1、观察者(订阅者)需要实现一个统一接口,接口中的内容主要是当被观察者发生改变时通知观察者时,观察者所作出的响应。

2、被观察者,主要的任务就是添加观察者,删除观察者,以及当自身发生改变时,将自身的改变都通知到每个订阅自己的观察者。

好了,下面我们自己手动实现这所有的一切。

Observer.java

/**
 * 观察者(订阅者)接口
 * @author Administrator
 *
 */
public interface Observer {
    public void notify(String msg);

    public String getName();
}

User.java

/**
 * 观察者(订阅者)
 */
public class User implements Observer{
    private String name;
    public void setName(String name) {
        this.name = name;
    }

    private Set<Product> focusPdts;

    public Set<Product> getFocusPdts() {
        return focusPdts;
    }

    public void setFocusPdts(Set<Product> focusPdts) {
        this.focusPdts = focusPdts;
    }

    public User(){
        focusPdts = new HashSet<Product>();
    }

    /**
     * 通知方法
     */
    @Override
    public void notify(String msg) {
        System.out.println(msg);
    }

    @Override
    public String getName() {

        return name;
    }


}

Product.java

/**
 * 商品-发布者-被观察者
 * 
 * @author Administrator
 * 
 */
public class Product {

    private String name;
    private double price;
    private List<Observer> focusUsers;// 观察者集合

    public Product(){    
        focusUsers = new ArrayList<Observer>();    
    }  

    /**
     * 价格折扣
     */
    public synchronized void payOff(double off) {

        this.price = getPrice() * (1 - off);
        StringBuffer msg = null;

        if(focusUsers!=null && !focusUsers.isEmpty()){
            Iterator it = focusUsers.iterator();
            while(it.hasNext()){
                Observer user = (Observer) it.next();

                String msgPart = ",《" + this.getName() +"》的价格"+this.getPrice() +",价格折扣"+off*100+"%";
                msg = new StringBuffer();

                msg.append("hello,"+user.getName());
                msg.append(msgPart);

                user.notify(msg.toString());
            }
        }
    }

    /**
     * 添加关注用户
     * 
     * @return
     */
    public void addFocusUsers(User user) {
        this.getFocusUsers().add(user);
    }

    /**
     * 删除关注的用户
     * 
     * @return
     */
    public void delFocusUser(User user) {
        this.getFocusUsers().remove(user);
    }

    public double getPrice() {

        return price;
    }

    void setPrice(double price) {
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<Observer> getFocusUsers() {
        return focusUsers;
    }

    public void setFocusUsers(List<Observer> focusUsers) {
        this.focusUsers = focusUsers;
    }
}

测试代码:
client.java

public class client {

    public static void main(String[] args) {
         //产品    
        Product mobile = new Product();    
        mobile.setName("SAMSUNG手机");    
        mobile.setPrice(2000);    

        Product book = new Product();    
        book.setName("JAVA设计模式");    
        book.setPrice(80);    

        //用户    
        User user1 = new User();    
        user1.setName("张三");    
        user1.getFocusPdts().add(mobile);//关注某一款三星手机    
        //user1.getFocusPdts().add(book);//关注JAVA设计模式    

        User user2 = new User();    
        user2.setName("李四");    
        user2.getFocusPdts().add(mobile);//关注某一款三星手机    
        user2.getFocusPdts().add(book);//关注JAVA设计模式    

        //建立商品和订阅者关联    
        mobile.addFocusUsers(user1);   
        book.addFocusUsers(user1);
        book.addFocusUsers(user2);

        //产品打折,发送站内信提醒 
        mobile.payOff(0.1);    
        book.payOff(0.2);    
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值