观察者模式适合于一对多的关系,当一发生变化的时候可以通知多的那一方。将一这一方成为主体,而多的一方则为观察者。例如天气预报,当天气发生变化的时候即可通知已经订阅的观察者。而观察者不想被通知天气变化的时候也十分方面就可以取消订阅。
观察者模式的优缺点
优点
1.主题和观察者是抽象耦合 2.一键式的通知方式
缺点
1.如果观察者过多,通知效率低下2.观察者只能得到变化后的结果而不能知道变化的过程。
观察者模式的实现
首先我们要定义一个抽象主体类。所有的主题都通过继承这个抽象类来实现具体的主题。这个抽象主体中要编写一个notifyobservers方法,通过这个方法来通知所有的观察者。所以update()方法即为每个观察者的更新方法。
1.抽象主题
public abstract class subject {
private List<observer> observers = new ArrayList<observer>(); // 作为观察者数组
public void addObserver(observer observer) {
observers.add(observer);
}
public void removeObserver(observer observer) {
observers.remove(observer);
}
public void notifyobservers() {
for (observer observer : observers) {
observer.update(this);
}
}
}
抽象主题已经有了之后就要有观察者,我们也要定义一个抽象的观察者,为所有的具体观察者定义一个更新接口。在抽象主题中已经对观察者定义了一个update方法,这边要定义update方法。
2.抽象观察者接口
public interface observer {
public void update(subject subject);
}
定义完抽象的接口,就要从抽象到具体,首先我们要写一个具体的主题。这个主题仅仅定义了一个消息属性,以及一个通知方法,通过此方法去调用抽象类的notifyobservers方法进行通知,同时将message内容赋予ConcreteSubject的message。让在update中可以调用到该属性。
3.具体主题类
public class ConcreteSubject extends subject {
private String message;
public String getMessage() {
return message;
}
public void noiftychange(String message) {
this.message = message;
notifyobservers();
}
}
完成了具体的主题,就剩下具体的观察者了。我们定一个name属性,用来知道每个观察者的姓名,实现observer接口,实现update方法 update方法就是具体的更新方式了。这边我们只是先通过输出到控制台的方式来表示更新。
4.具体观察者类
public class ConcreteObserver implements observer {
String name;
ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(subject subject) {
String message = ((ConcreteSubject) subject).getMessage();
System.out.println(name + "先生您收到的消息为:" + message);
}
}
5.测试类
从代码中可以看出通过观察者模式,我们可以很灵活的进行增加或者删除订阅者,统一发送消息。
public class ClientTest {
public static void main(String[] args) {
ConcreteSubject concreteSubject=new ConcreteSubject();
ConcreteObserver observer1=new ConcreteObserver("张");
ConcreteObserver observer2=new ConcreteObserver("王");
concreteSubject.addObserver(observer1);
concreteSubject.addObserver(observer2);
concreteSubject.noiftychange("今天气温要下降,请注意保暖");
concreteSubject.removeObserver(observer1);
concreteSubject.noiftychange("明天高温,请避免出门");
}
}