观察者模式主要解决的问题是一对多的依赖情况下,被依赖对象的消息通知问题,属于行为型设计模式。在程序设计的时候,有可能多个对象依赖同一个对象。当被依赖的这个对象有状态变更或者需要向依赖的类进行消息通知的时候,可以使用观察者模式。
实现方法:在观察者模式中,一般存在观察者角色,抽象观察者角色,被观察者角色(有的场景还会存在抽象被观察者的角色)。
- 观察者需要依赖被观察者,根据被观察者的某些状态改变而变更自己的状态。
- 被观察者对象中,会保存所有依赖该对象的观察者对象,当自身出现状态变更的时候,遍历观察者对象进行通知。
应用场景:观察者模式的使用场景就是一对多的对象依赖关系的场景,在实际生活中存在大量的观察者模式的例子(谁叫我们国家人多呢~)
- 电视转播是一种观察者模式,所有家庭中的电视都是观察者类对象,依赖电视台的记者,所以记者是被观察者类对象,当发生某种新闻或者事件,则向所有的电视客户端进行推送。
- 买房也是一种观察者模式的应用。开发商的置业顾问就是被观察者类的对象,而购房者都依赖置业顾问,是观察者类对象。当出现楼盘消息时候,置业顾问会遍历自己的用户列表,将消息通知到所有客户。
以上文提到的购房的场景为例。某一楼盘准备开盘,期间,会有很多的意向购房者(观察者类)前去看房,到了销售大厅之后,一般会有一个置业顾问(被观察者类)进行接待,介绍楼盘情况。最后,购房者会向置业顾问交换联系方式(形成依赖)。当后续楼盘有什么价格公布之类的消息的时候,置业顾问会向所有自己接待的客户发送消息(遍历观察者类,进行消息通知)。
实现抽象观察者
public interface Customer {
void action();
void inform();
}
观察者
public class HomeBuyer implements Customer
{
private Salesperson salesperson;
private String name;
public HomeBuyer(String name, Salesperson salesperson) {
this.name = name;
this.salesperson = salesperson;
this.salesperson.addCustomer(this);
}
@Override
public void action() {
System.out.println(this.name + ":让我思考一下要不要买房。");
}
@Override
public void inform() {
System.out.println(this.name + ":收到信息:" + this.salesperson.getInfo());
action();
}
}
被观察者
import java.util.ArrayList;
import java.util.List;
public class Salesperson
{
private List<Customer> customers = new ArrayList<Customer>();
private String info = null;
public void addCustomer(Customer customer)
{
this.customers.add(customer);
}
public void setMessage(String info)
{
this.info = info;
sendMessage();
}
public String getInfo() {
return info;
}
private void sendMessage()
{
for (Customer customer : customers)
{
customer.inform();
}
}
}
验证程序
public class Test {
public static void main(String[] args){
Salesperson salesperson = new Salesperson();
new HomeBuyer("购房者A", salesperson);
new HomeBuyer("购房者B", salesperson);
new HomeBuyer("购房者C", salesperson);
salesperson.setMessage("楼盘价格出来了,2万一平");
}
}
运行结果
购房者A:收到信息:楼盘价格出来了,2万一平
购房者A:让我思考一下要不要买房。
购房者B:收到信息:楼盘价格出来了,2万一平
购房者B:让我思考一下要不要买房。
购房者C:收到信息:楼盘价格出来了,2万一平
购房者C:让我思考一下要不要买房。Process finished with exit code 0
总结
优点:形成触发机制。
缺点:注意避免循环依赖。观察者中的处理状态变更的方法最好做成异步的,避免因为某个一个观察者的处理错误导致整个系统无法进行。