设计模式系列之「观察者模式」

1,963 阅读5分钟

最近小Y在看《反黑》这部剧,最引人回味的是堪称经典的山鸡哥飞上枝头变凤凰,当初的古惑仔弃暗投明做警察,可谓是涅槃重生啊。

张sir: 山鸡,和兴盛最近很嚣张啊,该是你大展身手的时候了,你要以最短时间打入他们内部获取犯罪证据,同时你要更名为凤凰,UnderStand?

凤凰仔: Yes,Sir。

经过一段时间潜伏,凤凰哥终于打入和兴盛内部,成为韩彬的一把手。时刻监视着大佬们的一举一动。

凤凰仔: 张sir,和兴盛大佬们齐聚一起,准备搞场大龙凤,你立马拖班人马过来压压惊,顺便来了一锅端。

根据凤凰监提供的证据,警方成功把这个社团搞得鸡飞狗跳。最后凤凰仔用枪指着韩彬的头来了一句:一直在你身边的警察,是我。来了一个一百八十度的转弯,山鸡变凤凰。

凤凰哥、Laughing哥是港剧卧底的佼佼者,让人赞不绝口。在设计模式中,照样有充当这样角色的存在——观察者模式

一、基本概念

1.定义

观察者模式也叫做发布订阅模式,定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

2.角色介绍

  • Subject被观察者
    定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须**实现的职责:**管理观察者并通知观察者。

  • Observer观察者
    观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。

  • ConcreteSubject具体的被观察者
    定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。

  • ConcreteObserver具体的观察者
    每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。

3.观察者模式的使用场景

  • 跨系统的消息交换场景,如消息队列的处理机制。
  • 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
  • 事件多级触发场景。

二、观察者模式演绎山鸡变凤凰

在反黑组在监视这几位大佬的同时,商业调查科等等其他警察部门也在监视着,为了使各部门行动统一,凤凰仔收集到的证据统一使用,根据其反馈回来的消息,各部门做相应的准备。

1.具体角色分配UML

2.代码实现

①和兴盛的抽象被观察者

public abstract class HeXingSheng {

	//保存监视和兴的警察部门
	private List<Police> polices=new ArrayList<>();
	//增加监听的警察部门
	public abstract void addPoliceObserver(Police police);
	//删除监听的警察部门
	public abstract void deletePoliceObserver(Police police);
	//通知每个监听部门作出反应
	public abstract void notifyPolices(String tip);

}

②和兴盛大佬们的具体被观察类

public class HeadOfGang extends HeXingSheng {
	@Override
	public void addPoliceObserver(Police police) {
		this.polices.add(police);
	}

	@Override
	public void deletePoliceObserver(Police police) {
		this.polices.remove(police);
	}

	@Override
	public void notifyPolices(String tip) {
		for(Police police:polices){
			police.action(tip);
		}
	}
}

③警察部门的抽象观察者

public abstract class Police {
	//根据信息作出反应
	public abstract void action(String action);
}

④反黑组

public class FanHeiTeam extends Police {
	@Override
	public void action(String action) {
		System.out.println("卧底凤凰提供的情报:"+action);
		System.out.println("反黑组根据情报对和兴盛进行相关黑社会行为进行控告。");
	}
}

⑤商业调查科

public class ShangYeTeam extends Police{

	@Override
	public void action(String action) {
		System.out.println("卧底凤凰提供的情报:"+action);
		System.out.println("商业调查科根据情报对和兴盛进行相关商业行为进行控告。");
	}
}

⑥Client

public class Client {

	public static void main(String[] args) {
		//被观察的对象-和兴盛
		HeXingSheng xingSheng=new HeadOfGang();
		//观察对象-反黑组、商业调查科
		Police fanHeiTeam=new FanHeiTeam();
		Police shangye=new ShangYeTeam();
		//增加观察者
		xingSheng.addPoliceObserver(fanHeiTeam);
		xingSheng.addPoliceObserver(shangye);
		//凤凰仔收集到证据,通知各部门准备行动
		xingSheng.notifyPolices("和兴盛大佬们聚在一起搞龙凤。");
	}
}

输出的结果为:

//反黑组 
卧底凤凰提供的情报:和兴盛大佬们聚在一起搞龙凤。
反黑组根据情报对和兴盛进行相关黑社会行为进行控告。

//商业调查科
卧底凤凰提供的情报:和兴盛大佬们聚在一起搞龙凤。
商业调查科根据情报对和兴盛进行相关商业行为进行控告。

三、观察者模式优缺点

1.优点

  • 观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。
  • 观察者和被观察者之间是抽象耦合。则不管是增加观察者还是被观察者都非常容易扩展,而且在Java中都已经实现的抽象层级的定义,在系统扩展方面更是得心应手。

2.缺点

  • 如果一个被观察者对象有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间,效率让人担忧。

  • 一个被观察者,多个观察者,开发和调试就会比较复杂,而且在Java中消息的通知默认是顺序执行,一个观察者卡壳,会影响整体的执行效率。在这种情况下,一般考虑采用异步的方式。

四、总结

观察者模式在项目中非常常用,但是从上面页面知道观察者模式也相对存在着缺点,一是广播链的问题。另外一个就是异步处理问题,在开发中需要格外注意。

Android技术交流吧