设计模式之观察者模式
设计模式之观察者模式
1.观察者模式介绍
1.1> 设计模式可以说是一种代码规范,也可以说是一种前人总结的技巧经验,对于后来编程者,学习设计模式可以对编程思路有一些启发,其中也包括经验启发。
1.2> 对象之间定义一对多的依赖关系,当一个对象发生变化时,依赖它的其他对象会收到通知并相应作出反应。发生改变的对象称之为观察目标(被观察者),收到通知并作出反应的对象称之为观察者。一个观察目标可以有多个观察者,观察者之间相互没有任何关系,可以增加、删除观察者。
2.观察者模式应用场景
2.1> 基础的发布、订阅关系,比如:博主的粉丝订阅,博主有更新或者回复的时候,给粉丝发生通知,
2.2> 有一个微信公众号服务,不定时发布一些消息,关注公众号就可以收到推送消息,取消关注就收不到推送消息。
2.3> 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
3.观察者模式代码详解?
3.1> 观察者模式的结构
观察者模式与发布/订阅模式的区别在于;通知调度的地方,观察者模式中,通知调度的地方在于被观察者中,而发布/订阅模式中有一个专门的调度中心。
3.2> 观察者模式中主要的对象:2个接口;2个类
观察目标(被观察者)的抽象接口:观察目标将观察者保存在一个集合中,一个被观察者可以有多个观察者;观察目标提供了 增加观察者、删除观察者的接口。
观察者的抽象接口:为所有具体的观察者提供一个接口,用于被观察者发生改变时更新自己。
被观察者的抽象类:存储之被观察者的对象,当其发生改变时,给所有关注的观察者发送通知,一般通过具体的子类来实现。
观察者抽象类:存储相关状态,通过具体子类实现观察者的抽象接口,通过被观察者的状态更新自己。
3.3>
观察目标抽象接口:
public interface BeObserver {
void addObserver(AbstractObserverDTO abstractObserverDTO);
void delObserver(AbstractObserverDTO abstractObserverDTO);
void notice(MessageDTO messageDTO);
}
定义了三个接口
1> 增加观察者。
2> 删除观察者。
3> 通知观察者,自身发送改变,通知观察者。
被观察者抽象类,具体子类继承该类
public class AbstracBeObserverDTO implements BeObserver {
private String name;
private String age;
private List<AbstractObserverDTO> abstractObserverDTOS = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public void addObserver(AbstractObserverDTO abstractObserverDTO) {
abstractObserverDTOS.add(abstractObserverDTO);
}
@Override
public void delObserver(AbstractObserverDTO abstractObserverDTO) {
abstractObserverDTOS.remove(abstractObserverDTO);
}
@Override
public void notice(MessageDTO messageDTO) {
if (abstractObserverDTOS == null || abstractObserverDTOS.size() == 0) {
return;
}
for (AbstractObserverDTO abstractObserverDTO : abstractObserverDTOS) {
abstractObserverDTO.updateMsg(messageDTO);
}
}
}
实现了被观察者的3个接口。具体的子类继承该抽象类,重写该类的接口。
public interface Observer {
/**
* 观察者更新的方法
*
* @param messageDTO
*/
void updateMsg(MessageDTO messageDTO);
}
观察者抽象接口:主要是当被观察发生变更时,调用该方法通知观察者
观察者抽象类,实现了观察者首相接口
public class AbstractObserverDTO implements Observer {
private String name;
private Date date;
private List<AbstractObserverDTO> abstractObserverDTOS = new ArrayList<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
@Override
public void updateMsg(MessageDTO messageDTO) {
System.out.println(this.name + ":" + messageDTO.getName() + ":" + messageDTO.getMessage());
}
}
具体当观察者子类继承该类,并重写该方法。
消息对象
public class MessageDTO {
private String message;
private Integer type;
private String name;
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
别观察者子类
public class BeObserverOneDTO extends AbstracBeObserverDTO {
private String note;
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
观察者子类1
public class ObserverOneDTO extends AbstractObserverDTO {
private String note;
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
@Override
public void updateMsg(MessageDTO messageDTO) {
System.out.println(this.note + ":" + messageDTO.getName() + ":" + messageDTO.getMessage());
}
}
观察者子类2
public class ObserverTwoDTO extends AbstractObserverDTO {
private String note;
private String sex;
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public void updateMsg(MessageDTO messageDTO) {
System.out.println(this.note + ":" + messageDTO.getName() + ":" + messageDTO.getMessage());
}
}
测试
public class TestMain {
public static void main(String[] args) {
ObserverOneDTO one = new ObserverOneDTO();
one.setNote("粉丝1");
ObserverTwoDTO two = new ObserverTwoDTO();
two.setNote("粉丝2");
two.setSex("女");
BeObserverOneDTO beObserverOneDTO = new BeObserverOneDTO();
beObserverOneDTO.setNote("zuiaicy");
beObserverOneDTO.setName("zuiaicy有博客更新");
beObserverOneDTO.addObserver(one);
beObserverOneDTO.addObserver(two);
MessageDTO messageDTO = new MessageDTO();
messageDTO.setMessage("设计模式之观察者模式");
messageDTO.setName(beObserverOneDTO.getName());
messageDTO.setType(1);
beObserverOneDTO.notice(messageDTO);
}
}
测试结果:
粉丝1:zuiaicy有博客更新:设计模式之观察者模式
粉丝2:zuiaicy有博客更新:设计模式之观察者模式
优化:
1> 被观察者的订阅列表(观察者列表)可以存数据库。
2> 被观察者发生变更时,可以通过异步方式调用观察者的更新接口。
3> 许多地方还可以做得更加抽象。
4.观察者模式的优缺点?
优点:
1> 面向接口编程的思想
2> 松耦合,改变了一方,不会影响到另一方。
3> 观察者模式可以实现表示层和数据逻辑层的分离,定义了稳定的消息更新传递机制,并抽象了更新接口,使得可以有各种各样不同的表示层充当具体观察者角色。
4> 观察者模式支持广播通信,观察目标会向所有已注册的观察者对象发送通知,简化了一对多系统设计的难度。
5> 观察者模式满足“开闭原则”的要求,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下,增加新的观察目标也很方便。
不足:
1> 如果一个观察目标对象有很多直接和间接观察者,将所有的观察者都通知到会花费很多时间。
2> 如果在观察者和观察目标之间存在循环依赖,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3> 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。