观察者模式多应用预警提醒等系统,当目标对象发生改变时,会自动通知相关的观察者。例如:高档小区的监控系统,银行预警系统,地震预警系统,温度预警系统等。
以温度预警系统为例来说明观察者模式:
当气象部门获取温度超过某一阈值时,会向政府、单位、个人发出高温预警通知。
如图,观察对象和观察者之间的关系是一对多的依赖关系,当观察对象发生改变时,依赖于它的观察者都要做出应急处理。
设计静态图如下:
---------代码设计如下------------
观察对象接口:
package com.test.observe;
public interface ISubject {
void add(IObserver o);
void remove(IObserver o);
void notifyAllObserver();
void setTemperature(int temperature);
String getTemperature();
String getLevel();
}
观察者接口:
package com.test.observe;
public interface IObserver {
public void update(ISubject o);
}
观察对象实现类:
package com.test.observe;
import java.util.Iterator;
import java.util.Vector;
public class Subject implements ISubject{
private Vector<IObserver> observers;
private String level;
private int temperature;
public Subject() {
observers = new Vector<IObserver>();
}
public void add(IObserver o) {
observers.add(o);
}
public void remove(IObserver o) {
observers.remove(o);
}
public void notifyAllObserver() {
System.out.println("气象通知:");
Iterator<IObserver> iterator = observers.iterator();
while(iterator.hasNext()){
(iterator.next()).update(this);
}
}
public void setTemperature(int temperature) {
this.temperature = temperature;
this.earlyWarning();
}
public String getTemperature() {
return "温度"+this.temperature;
}
public String getLevel() {
return this.level + "预警,";
}
private void earlyWarning() {
if(temperature>30 && temperature<35){
this.level = "黄色";
}else if(temperature>35 && temperature<40){
level = "橙色";
}else if(temperature>40){
level = "红色";
}else{
level = "天蓝色";
}
this.notifyAllObserver();
}
}
观察者(政府):
package com.test.observe;
public class Goverment implements IObserver {
public void update(ISubject o) {
System.out.println("政府收到温度预警:" + o.getLevel() + o.getTemperature());
}
}
观察者(个人):
package com.test.observe;
public class Person implements IObserver {
public void update(ISubject o) {
System.out.println("个人收到温度预警:" + o.getLevel() + o.getTemperature());
}
}
测试类:
package com.test.observe;
import java.util.Random;
import com.test.observe.adddecorator.DecoratorA;
import com.test.observe.adddecorator.DecoratorB;
public class Client {
public static void main(String[] args) {
Person p = new Person();
Goverment g = new Goverment();
ISubject sub = new Subject();
sub.add(p);
sub.add(g);
Random r = new Random();
int rom = r.nextInt(20) + 30; //生成 >=30 and <=50 的随机数
sub.setTemperature(rom);
}
}
输出结果:
气象通知:
个人收到温度预警:橙色预警,温度38
政府收到温度预警:橙色预警,温度38
上面观察者模式用vector是有道理的,vector是线程安全的,比如推送的是广告,如果你用的是线程非安全的arraylist,那么同一条广告信息,可能存在推送给一个观察者两次或者多次,同样的信息每天推送两次或者三次,这样的app是不是有卸掉应用的冲动。
vector中源码扩容有两种策略:一种是自定义扩容,每次扩容都是初始值+扩容值;另一种是默认扩容,初始值*2,vector的默认值是10,也可自定义默认值。
下面把vector扩容的源码贴上:
/**
* This implements the unsynchronized semantics of ensureCapacity.
* Synchronized methods in this class can internally call this
* method for ensuring capacity without incurring the cost of an
* extra synchronization.
*
* @see #ensureCapacity(int)
*/
private void ensureCapacityHelper(int minCapacity) {
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object[] oldData = elementData;
int newCapacity = (capacityIncrement > 0) ?
(oldCapacity + capacityIncrement) : (oldCapacity * 2);
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
为什么没有加Synchronized呢,上面有解释:“此类中的同步方法可以在内部调用此方法来确保容量,而不会产生额外同步的成本。”, public synchronized void addElement(E obj) ,addElement已经是同步方法,ensureCapacityHelper作为它内部的方法,不用再加锁,可以避免增加额外的开销。
--------观察者结束------------
--------下面配合装饰者使用--------
现在不只有个人和政府需要气象部门系统通知,现在有交通局,民政局,路政局等等部门需要通知,
且增加了对预警信息的应对措施,为了防止继承或者实现类太多,导致类爆炸,可以使用装饰者。
结构图(略粗糙):
装饰者代码如下:
package com.test.observe.adddecorator;
import com.test.observe.IObserver;
import com.test.observe.ISubject;
public abstract class Decorator implements IObserver {
private IObserver observer;
public Decorator(IObserver observer) {
this.observer = observer;
}
@Override
public void update(ISubject o) {
System.out.println("------");
System.out.println("装饰者收到温度预警:" + o.getLevel() + o.getTemperature());
}
}
具体装饰者:
package com.test.observe.adddecorator;
import com.test.observe.IObserver;
import com.test.observe.ISubject;
public class DecoratorA extends Decorator{
public DecoratorA(IObserver observer) {
super(observer);
}
public void quickEnterFunkHole(){
System.out.println("DecoratorA-交通局:"+"热死了,快进入防空洞");
}
@Override
public void update(ISubject o) {
super.update(o);
this.quickEnterFunkHole();
}
}
package com.test.observe.adddecorator;
import com.test.observe.IObserver;
import com.test.observe.ISubject;
public class DecoratorB extends Decorator{
public DecoratorB(IObserver observer) {
super(observer);
}
public void quickEnterFunkHole(){
System.out.println("DecoratorB-民政局:"+"热死了,快进入防空洞");
}
@Override
public void update(ISubject o) {
super.update(o);
this.quickEnterFunkHole();
}
}
测试类:
package com.test.observe;
import java.util.Random;
import com.test.observe.adddecorator.DecoratorA;
import com.test.observe.adddecorator.DecoratorB;
public class Client {
public static void main(String[] args) {
Person p = new Person();
Goverment g = new Goverment();
DecoratorA a = new DecoratorA(p);
DecoratorB b = new DecoratorB(p);//这块属于增加的装饰者模式,对观察者进行包装:比如现在有交通局,民政局,路政局等等部门需要通知,
//且增加了对预警信息的应对措施,为了防止继承或者实现类太多,导致类爆炸,可以使用装饰者。
ISubject sub = new Subject();
sub.add(p);
sub.add(g);
sub.add(a);//这块属于增加的装饰者模式
sub.add(b);
Random r = new Random();
int rom = r.nextInt(20) + 30; //生成 >=30 and <=50 的随机数
sub.setTemperature(rom);
}
}
输出结果:
气象通知:
个人收到温度预警:红色预警,温度41
政府收到温度预警:红色预警,温度41
------
装饰者收到温度预警:红色预警,温度41
DecoratorA-交通局:热死了,快进入防空洞
------
装饰者收到温度预警:红色预警,温度41
DecoratorB-民政局:热死了,快进入防空洞
观察者模式配合装饰者模式结束!
End!