共计 4764 个字符,预计需要花费 12 分钟才能阅读完成。
一、观察者模式介绍
1. 解决的问题
次要解决将一个对象的状态扭转告诉给其余对象的问题。
2. 定义
观察者模式 是一种行为设计模式,容许你定义一种订阅机制,可在对象事件产生时告诉多个“察看”该对象的其余对象。
3. 利用场景
- 当一个对象的扭转须要扭转其余对象,或理论对象时是当时未知的或动态变化时,可应用观察者模式。
- 当利用中的一些对象必须察看其余对象时,可应用观察者模式,但仅能在无限工夫内或特定状况下应用。
二、观察者模式优缺点
1. 长处
- 开闭准则:无需批改发布者代码就能引入新的订阅者(如果是发布者接口,则可轻松引入发布者类)。
- 能够在运行时建设与对象之间的分割。
2. 毛病
- 订阅者的告诉程序是随机的。
三、观察者模式利用实例:您的快递已达到蜂站,请及时签收
1. 实例场景
当初大部分快递都不会交付到手上了,除非咱们特意选了上门服务。
个别都是买完两三天,收到条短信:您好,您的快递已到蜂站,请凭取件码 K16888 取件,取件工夫 09:30-21:00,请及时取件。
刚看完短信,APP 也跳出一则告诉:您的快递已被蜂站签收,请及时取件。
明天,就以快递达到,同时收到 APP 和短信告诉为例,介绍一下观察者模式。
2. 观察者模式实现
2.1 工程构造
observer-pattern
└─ src
├─ main
│ └─ java
│ └─ org.design.pattern.observer
│ ├─ model
│ │ ├─ ExpressPackage.java
│ │ ├─ Courier.java
│ │ └─ User.java
│ ├─ subscriber
│ │ ├─ ExpressEventSubscriber.java
│ │ └─ impl
│ │ ├─ AppExpressEventListener.java
│ │ └─ SmsExpressEventSubscriber.java
│ ├─ publisher
│ │ └─ ExpressEventPublisher.java
│ └─ service
│ ├─ ExpressService.java
│ └─ impl
│ └─ ExpressServiceImpl.java
└─ test
└─ java
└─ org.design.pattern.observer.test
└─ ExpressEventTest.java
2.2 代码实现
2.2.1 实体类
快递实体类
/**
* 快递
*/
@Getter
@Setter
@AllArgsConstructor
public class Express {
/**
* 快递 id
*/
private String id;
/**
* 收件人名称
*/
private String recipientName;
/**
* 收件人打电话
*/
private String recipientPhone;
/**
* 收件人地址
*/
private String recipientAddress;
}
2.2.2 发布者
快递事件发布者
/**
* 快递事件发布者
*/
public class ExpressEventPublisher {
/**
* 快递事件订阅者列表
*/
private List<ExpressEventSubscriber> subscriberList = new ArrayList<>();
/**
* 订阅快递事件
*
* @param expressEventSubscriber 订阅者
*/
public void subscribe(ExpressEventSubscriber expressEventSubscriber) {subscriberList.add(expressEventSubscriber);
}
/**
* 勾销订阅快递事件
*
* @param expressEventSubscriber 订阅者
*/
public void unsubscribe(ExpressEventSubscriber expressEventSubscriber) {subscriberList.remove(expressEventSubscriber);
}
/**
* 告诉订阅者快递达到
*
* @param express 快递
*/
public void notifySubscribersArrive(Express express) {subscriberList.forEach(expressEventSubscriber -> expressEventSubscriber.arrive(express));
}
}
2.2.3 订阅者
快递事件订阅者接口
/**
* 快递事件订阅者接口
*/
public interface ExpressEventSubscriber {
/**
* 快递达到
*
* @param express 快递
*/
void arrive(Express express);
}
App- 快递事件订阅者
/**
* App- 快递事件订阅者
*/
@Slf4j
public class AppExpressEventListener implements ExpressEventSubscriber {
/**
* 快递达到
*
* @param express 快递
*/
@Override
public void arrive(Express express) {log.info("App 告诉:您的包裹 {} 已达到蜂站!", express.getId());
}
}
短信 - 快递事件订阅者
/**
* 短信 - 快递事件订阅者
*/
@Slf4j
public class SmsExpressEventSubscriber implements ExpressEventSubscriber {
/**
* 快递达到
*
* @param express 快递
*/
@Override
public void arrive(Express express) {log.info("短信告诉:您的包裹 {} 已达到蜂站!", express.getId());
}
}
2.2.4 服务类
快递服务接口
/**
* 快递服务接口
*/
public interface ExpressService {
/**
* 快递已达到
*
* @param express 快递
*/
void arrive(Express express);
}
快递服务实现类
/**
* 快递服务实现类
*/
@Slf4j
public class ExpressServiceImpl implements ExpressService {
/**
* 快递事件发布者
*/
private final ExpressEventPublisher expressEventPublisher;
/**
* 构造方法
*
* @param expressEventPublisher 快递事件发布者
*/
public ExpressServiceImpl(ExpressEventPublisher expressEventPublisher) {this.expressEventPublisher = expressEventPublisher;}
/**
* 快递达到
*
* @param express 快递
*/
@Override
public void arrive(Express express) {log.info("{}的快递已达到蜂站!", express.getRecipientName());
expressEventPublisher.notifySubscribersArrive(express);
}
}
2.3 测试验证
2.3.1 测试验证类
/**
* 快递事件测试类
*/
public class ExpressEventTest {
@Test
public void test() {
// 快递初始化
Express express = new Express("1", "yiyufxst", "13245678910", "xx 路");
// 订阅者初始化
ExpressEventSubscriber appExpressEventListener = new AppExpressEventListener();
ExpressEventSubscriber smsExpressEventSubscriber = new SmsExpressEventSubscriber();
// 发布者初始化
ExpressEventPublisher expressEventPublisher = new ExpressEventPublisher();
// 订阅快递事件
expressEventPublisher.subscribe(appExpressEventListener);
expressEventPublisher.subscribe(smsExpressEventSubscriber);
// 快递服务类初始化
ExpressService expressService = new ExpressServiceImpl(expressEventPublisher);
// 快递达到
expressService.arrive(express);
// App 勾销订阅快递事件
expressEventPublisher.unsubscribe(appExpressEventListener);
// 模仿新快递
express.setId("2");
// 快递达到
expressService.arrive(express);
}
}
2.3.2 测试后果
14:50:01.090 [main] INFO o.d.p.o.s.impl.ExpressServiceImpl - yiyufxst 的快递已达到蜂站!14:50:01.093 [main] INFO o.d.p.o.s.i.AppExpressEventListener - App 告诉:您的包裹 1 已达到蜂站!14:50:01.093 [main] INFO o.d.p.o.s.i.SmsExpressEventSubscriber - 短信告诉:您的包裹 1 已达到蜂站!14:50:01.093 [main] INFO o.d.p.o.s.impl.ExpressServiceImpl - yiyufxst 的快递已达到蜂站!14:50:01.093 [main] INFO o.d.p.o.s.i.SmsExpressEventSubscriber - 短信告诉:您的包裹 2 已达到蜂站!Process finished with exit code 0
四、观察者模式构造
-
发布者(Publisher)会对其余对象发送值得关注的事件。事件会在发布者本身状态扭转或执行特定行为后产生。发布者中蕴含一个容许新订阅者退出或以后订阅者来到列表的订阅架构。
当新事件产生时,发送者会便当订阅者列表并调用每个订阅者对象的告诉办法。
- 订阅者(Subscriber)接口申明了告诉接口。在绝大多数状况下,该接口仅蕴含一个更新办法。该办法能够领有多个参数,以便发布者能在更新时传递工夫的详细信息。
-
具体订阅者(Concrete Subscribers)能够执行一些操作来回应发布者的告诉。所有订阅者类实现了同样的接口,因而发布者无需与具体类耦合。
订阅者通常须要一些上下文信息来正确地解决更新音讯。因而发布者会将一些上下文数据作为告诉办法的参数进行传递。发布者也可将本身作为参数传递,使订阅者间接获取所需的数据。
- 客户端(Client)会别离创立发布者和订阅者对象,而后为订阅者注册发布者更新。
设计模式并不难学,其自身就是多年教训提炼出的开发指导思想,关键在于多加练习,带着应用设计模式的思维去优化代码,就能构建出更正当的代码。
源码地址:https://github.com/yiyufxst/design-pattern-java
参考资料:
小博哥重学设计模式:https://github.com/fuzhengwei/itstack-demo-design
深刻设计模式:https://refactoringguru.cn/design-patterns/catalog