本文说明:在学习《Java EE互联网轻量级框架整合开发》此书时,里面提到了几种设计模式,我在学习这几种设计模式时写了笔记,放上来让大家共同学习,如果有错误,望指出。
本文章由两部分组成:
基本概念+关键代码讲解
完整例子
基本概念+关键代码讲解
观察者模式主要用在y随着x变而变的模型中。比如一个商家有了新产品,只跟京东、淘宝合作,那么就需要把这个新产品推送到京东和淘宝,那么就有了这段伪代码:
if(有新产品) {
推送到京东;
推送到淘宝;
}
如果又跟其他商家合作了,就得修改这段逻辑:
if(有新产品) {
推送到京东;
推送到淘宝;
推送到唯品会;
推送到当当网;
}
如果源源不断要跟新电商合作,源源不断增加新产品,就得不断修改这段逻辑,会导致这段逻辑非常复杂。
这里的自变量是“新产品”,因变量是“推送”。
如果我们可以修改成:京东淘宝唯品会当当网这些人来监听我是不是有新产品,我一增加新产品,它们就给我自动推送到他们的平台上。新增加一个合作电商,就把它扔进监听队列,这样的话会非常省事。
把监听这个动作换成观察,这样就有了观察者模式。
观察者模式有3种类:目标类(核心代码实现)、观察类、测试类。
【目标类】:就是被观察的对象,主要有两个核心动作,增加观察者和增加新产品。
【观察类】:观察目标,目标作出改变,自己就作出改变。
【测试类】:测试逻辑是否实现。
下面主要说说【目标类】和【观察类】。
目标类
我们可以假设产品列表为目标类,既然是目标,肯定有一堆产品对象,我们可以用一个List数组表示。产品增加,我们需要有一个维护产品增加时需要做的逻辑的方法:addProduct()。
那么观察类如何实现它的监听呢?产品变化时,会调用addProduct()方法,要使得观察类跟着变,那么必须把逻辑写到addProduct()里面去。但是如果硬写入,就没有意义了。我们可以利用接口,把接口抛出去让别人实现,然后我们这段随着x改变的y代码就能动态跟着变了。
这里我们得采用 java.util 包里面给我们提供的一些接口,在addProduct()写入一些通过接口能动态实现的方法:比如产品改变了,就“设置改变”,并“通知观察者”。理所当然的,我们的目标类还需要维护观察类的数组,所以与此同时也需要有一个方法能够增加观察者,将观察者加入到我们的目标类队列中。
我们要用到java给我们实现好的监听,可以继承 java.util.Observable 这个类,这样我们可以用到它给我们提供的方法:setChanged(),notifyObservers(),并且它自己给我们维护了一个观察类数组(查看源代码可知为:private Vector<Observer> obs;),也提供了一个维护此数组的方法:addObserver()。
加上我们自己维护的产品对象数组productList以及增加产品的方法addProduct(),将Observable提供给我们的方法按照一定逻辑写入,这个类的功能就基本完成了。实现如下:
//我们自己维护的产品列表数组
private List<String> productList = null;
//增加产品观察者
public void addProductListObserver(Observer observer) {
this.addObserver(observer); //Observable提供的方法
}
//增加产品及相应的操作
public void addProduct(String product) {
this.productList.add(product);
System.out.println("产品列表新增了产品:" + product);
this.setChanged(); //Observable提供的方法
this.notifyObservers(product); //Observable提供的方法
}
但还有一个问题。
如果每次增加新产品的时候都要new一个新的目标类对象,这样就乱套了。我们只需要一个目标类对象,每次调用时只需要拿到那个目标类对象再进行产品增加才对。所以我们这里需要用到单例模式——每次getInstance时,只得到原来new过的对象。如果没有,就现场给它new一个,代码如下:
//SingleExample类中
private static SingleExample instance = null;
private SingleExample() {} //使构造方法私有化才能禁止外界的new
private static SingleExample getInstance() {
if(instance == null) {
instance = new SingleExample();
}
return instance;
}
可以注意到这个getInstance()方法是静态的,所以它的对象也是静态的。
不过如果这个类还有别的属性,比如我们这个例子的产品列表数组,如果我们这个类也要单例的话,也必须实例化唯一一个产品列表数组,所以它也得保持着static,或者通过下面不需要static的方式实例化:
private static ProductList instance;
private List<String> productList = null;
private ProductList() {}
public static ProductList getInstance() {
if(instance == null) {
instance = new ProductList();
//注意这里非static对象的productList的实例化
instance.productList = new ArrayList<String>();
}
return instance;
}
这样我们就实现了目标类,完整代码见最后。
观察类
观察者模式主要逻辑都在被观察者上,观察类只需要实现很少的逻辑。它只需要实现 java.util.Observer 接口的update方法,把被观察者发生变化后需要做的逻辑(比如我们开头说的“推送”)写在update方法之中即可。比如我们可以实现如下:
package com.amiao.design_pattern.observer;
import java.util.Observable;
import java.util.Observer;
public class JingDong implements Observer {
@Override
public void update(Observable o, Object product) {
String newProduct = (String) product;
System.out.println("京东新增了产品——" + newProduct);
}
}
完整代码
//主要包含4个类:目标类,2个观察类,测试类
//目标类
package com.amiao.design_pattern.observer;
import java.util.ArrayList;
import java.util.List;
import java.util.Observable; //不要用javax的Observable接口,要用java.util的Observable类
import java.util.Observer;
public class ProductList extends Observable {
private List<String> productList = null;
private static ProductList instance;
private ProductList() {}
public static ProductList getInstance() {
if(instance == null) {
instance = new ProductList();
//注意这里非static对象的productList的实例化
instance.productList = new ArrayList<String>();
}
return instance;
}
public void addProductListObserver(Observer observer) {
this.addObserver(observer);
}
public void addProduct(String product) {
this.productList.add(product);
System.out.println("产品列表新增了产品:" + product);
this.setChanged();
this.notifyObservers(product);
}
}
//观察类1
package com.amiao.design_pattern.observer;
import java.util.Observable;
import java.util.Observer;
public class JingDong implements Observer {
@Override
public void update(Observable o, Object product) {
String newProduct = (String) product;
System.out.println("京东新增了产品——" + newProduct);
}
}
//观察类2
package com.amiao.design_pattern.observer;
import java.util.Observable;
import java.util.Observer;
public class TaoBao implements Observer {
@Override
public void update(Observable o, Object product) {
String newProduct = (String) product;
System.out.println("淘宝新增了产品——" + newProduct);
}
}
//测试类
package com.amiao.design_pattern.observer;
public class TestMain {
public static void main(String[] args) {
ProductList productList = ProductList.getInstance();
productList.addObserver(new JingDong());
productList.addObserver(new TaoBao());
productList.addProduct("酸梅巧克力");
productList.addProduct("雪媚冰淇淋");
}
}
/*
* 运行结果
* 产品列表新增了产品:酸梅巧克力
* 淘宝新增了产品——酸梅巧克力
* 京东新增了产品——酸梅巧克力
* 产品列表新增了产品:雪媚冰淇淋
* 淘宝新增了产品——雪媚冰淇淋
* 京东新增了产品——雪媚冰淇淋
* */