一、什么是观察者模式
观察者模式属于行为型设计模式。它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。
二、什么时候用观察者模式
首先,察者模式属于行为型模式。当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,所有依赖于它的对象都应该受到通知并且自动更新,那么可使用本模式。
三、有哪些组成
观察者模式包括以下几个部分:
-
Subject(主题,被观察者):定义了一个一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。主题对象通常会维护一个观察者列表,并提供方法用于注册、移除和通知观察者。
-
Observer(观察者):定义了一个更新接口,当被观察对象的状态发生变化时能够得到通知。观察者一般会注册到主题对象中,以便主题对象状态改变时能够及时得到通知并作出相应处理。
-
ConcreteSubject(具体主题):具体的主题对象,维护具体观察者对象的状态,当状态发生变化时通知所有注册的观察者。
-
ConcreteObserver(具体观察者):具体的观察者对象,实现了观察者接口中定义的更新方法,在接收到主题对象通知时进行相应的处理。
-
Notification(通知):通知是被观察者发出的一种消息,用于告知观察者发生了变化。通知可以附带一些额外的数据,以便观察者能够获取变化的具体信息。
通过各部分间的协作,实现了对象之间的解耦,使得一个对象发生变化时能够自动通知其他对象。
四、有哪些不足
-
过多细粒度的通知:当主题对象状态频繁变化时,观察者可能会收到大量的通知,这可能导致性能上的开销。
-
可能引发循环依赖:观察者和主题之间是一个松散的耦合关系,但在实际应用中,如果设计不合理,可能会出现观察者和主题相互依赖的情况,这可能会导致设计上的混乱。
-
定位困难:在某些情况下,观察者模式的使用可能会导致代码的执行路径变得复杂,使得定位问题变得困难。
-
可能引起内存泄漏:如果观察者没有被正确地移除或者被错误地持有,可能会导致内存泄漏问题。
-
通知顺序不确定:观察者模式中,观察者接收到通知的顺序是不确定的,这可能会导致一些潜在的问题。
五、示例代码
这里我用学生接收不同群消息的例子来说明本例子的使用。
//Observer(观察者)接口,本题看成所有订阅了这个群的学生
interface Student {
void update();
}
//ConcreteObserver(具体的观察者)类
public class ConcreteStudent implements Student {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ConcreteGroup getGroup() {
return group;
}
public void setGroup(ConcreteGroup group) {
this.group = group;
}
private ConcreteGroup group;
public ConcreteStudent(String name, ConcreteGroup group) {
this.name = name;
this.group = group;
}
public void update() {
System.out.println("Observer " + name + " received update. New notification: " + group.getNotification().getContent());
}
}
//Subject(被观察者)接口,这里看成群
public interface Group {
void attach(ConcreteStudent observer);
void detach(ConcreteStudent observer);
void notifyStudents();
}
//ConcreteSubject(具体的被观察者)类 有一个订阅者列表
class ConcreteGroup implements Group {
private String Name;
public ConcreteGroup(String name) {
super();
Name = name;
}
private List<ConcreteStudent> Students = new ArrayList<>();
private Notification notification;
public void attach(ConcreteStudent Student) {
System.out.println(Student.getName()+"加入群聊:"+Name);
Students.add(Student);
}
public void detach(ConcreteStudent Student) {
System.out.println(Student.getName()+"退出群聊"+Name);
Students.remove(Student);
}
public void notifyStudents() {
for (ConcreteStudent Student : Students) {
Student.update();
}
}
public void setNotification(Notification notification) {
// TODO Auto-generated method stub
this.notification = notification;
notifyStudents();
}
public Notification getNotification() {
// TODO Auto-generated method stub
return notification;
}
}
public class Notification {
private String content;
private Date publicateTime;
public Notification(String content, Date publicateTime) {
this.content = content;
this.publicateTime = publicateTime;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getPublicateTime() {
return publicateTime;
}
public void setPublicateTime(Date publicateTime) {
this.publicateTime = publicateTime;
}
}
public class MainTest {
public static void main(String[] args) {
ConcreteGroup group = new ConcreteGroup("快乐学习");
ConcreteStudent student1 = new ConcreteStudent("Student1", group);
ConcreteStudent student2 = new ConcreteStudent("Student2", group);
group.attach(student1);
group.attach(student2);
Date date = new Date();
group.setNotification(new Notification("快写pta",date));
group.detach(student1);
Date date2 = new Date();
group.setNotification(new Notification("快写课堂作业",date2));
}
}