观察者模式 及 观察者与装饰者配合使用

观察者模式多应用预警提醒等系统,当目标对象发生改变时,会自动通知相关的观察者。例如:高档小区的监控系统,银行预警系统,地震预警系统,温度预警系统等。

以温度预警系统为例来说明观察者模式:

当气象部门获取温度超过某一阈值时,会向政府、单位、个人发出高温预警通知。


如图,观察对象和观察者之间的关系是一对多的依赖关系,当观察对象发生改变时,依赖于它的观察者都要做出应急处理。

设计静态图如下:


---------代码设计如下------------

观察对象接口:

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!


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值