一、设计模式分类
行为型:通过类之间不同通信方式实现不同行为。包括责任链/命名/解释器/迭代器/中介者/备忘录/观察者/状态/策略/模板/访问者模式。
三、行为型模式
1. 模板模式
什么是模板模式?
- 模板模式是一种行为型设计模式,它定义了一个算法的骨架,将一些步骤的实现延迟到子类中。在模板模式中,父类定义了一个模板方法,该方法包含了算法的骨架,而具体的实现细节由子类来完成。
应用场景:
- 当算法的执行流程是固定的,但具体步骤的实现可能会有所不同时,可以使用模板模式来灵活实现算法。
- 当多个类具有相似的行为时,可以将这些行为抽象到一个模板类中,并通过子类来实现具体的行为差异。
优点:
- 提供了代码的复用性:将算法的公共部分提取到抽象模板中,可以避免在每个具体类中重复编写相同的代码。
- 扩展和维护更简单:子类可以在不修改算法骨架的情况下能够灵活地修改具体步骤的实现。
案例:
下面是一个简单的模板模式案例,以制作咖啡和茶为例:
// 模板类
abstract class BeverageTemplate { // 创建一个饮料模板类,有一个prepare方法来制作饮料
// 制作饮料的方法。每种饮料的制作流程都一样,都要经过烧水--冲泡--倒入杯子--添加调味品这四个步骤,所以把四个步骤在prepare方法中定义好,然后将要让子类实现的具体步骤(brew、addCondiments)定义为抽象方法,让不同的子类去实现不同的逻辑
public final void prepare() {
boilWater();
brew();
pourInCup();
addCondiments();
}
public void boilWater() {
System.out.println("烧水");
}
public abstract void brew();
public abstract void addCondiments();
public void pourInCup() {
System.out.println("倒入杯子");
}
}
// 咖啡类,继承自模板类
class Coffee extends BeverageTemplate {
@Override
public void brew() {
System.out.println("冲泡咖啡");
}
@Override
public void addCondiments() {
System.out.println("加入牛奶和糖");
}
}
// 茶类,继承自模板类
class Tea extends BeverageTemplate {
@Override
public void brew() {
System.out.println("浸泡茶叶");
}
@Override
public void addCondiments() {
System.out.println("加入柠檬");
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
BeverageTemplate coffee = new Coffee();
System.out.println("制作咖啡:");
coffee.prepare();
System.out.println();
BeverageTemplate tea = new Tea();
System.out.println("制作茶:");
tea.prepare();
}
}
输出:
java/Spring 中的模板模式有哪些?
Spring 中 jdbcTemplate
、redisTemplate
等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。 jdbcTemplate
、redisTemplate
自动管理连接的获取和释放、无需编写繁琐的底层命令,开发者只需要关注SQL语句和参数即可。
2. 观察者模式
什么是观察者模式?
- 观察者模式是一种行为型设计模式,当一个对象(主题/被观察者)状态发生变化时,所有该对象的关注者(观察者)均能收到状态变化通知,以进行相应的处理。
- 在观察者模式中,主题维护了一个观察者列表,并提供注册、注销和通知的方法。观察者则实现了一个更新接口,用于接收主题发送的通知并执行相应的操作。当主题的状态发生改变时,它会遍历观察者列表,调用每个观察者的更新方法,从而实现了对象之间的松耦合。
应用场景:
-
实现事件驱动系统:当某个事件发生时,多个观察者可以监听该事件并作出响应,例如消息队列中的消息到达事件、Spring框架中的事件监听器等。具体场景例如,当用户提交订单后,需要通知库存管理系统减少库存,通知支付系统进行支付操作等。
-
发布-订阅模式:观察者模式可以用于实现发布-订阅模式,其中发布者(主题)发布消息,而多个订阅者(观察者)订阅并接收消息。
优点:
- 实现了对象间的松耦合:主题对象和观察者对象之间相互独立,两者之间的关联仅仅在于消息的通知。并且可以根据需求增加或删除观察者,而不需要修改主题对象。
- 支持广播通信。主题对象的状态变化会通知所有的观察者。
案例:
下面是一个简单的观察者模式的案例,假设有一个新闻发布系统,当发布新闻时,订阅者将收到通知并更新自己的状态:
// 主题(Subject)接口
interface Subject {
void registerObserver(Observer observer);
void deleteObserver(Observer observer);
void notifyObservers();
}
// 具体主题(ConcreteSubject)类
class NewsPublisher implements Subject {
private List<Observer> observers = new ArrayList<>(); // 维护一个观察者列表
private String news;
public void setNews(String news) { // 新的新闻到来时,主题对象的状态就认为发生了变化,所以要通知所有观察者
this.news = news;
notifyObservers();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void deleteObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(news);
}
}
}
// 观察者(Observer)接口
interface Observer {
void update(String news);
}
// 具体观察者(ConcreteObserver)类
class Subscriber implements Observer {
private String name;
public Subscriber(String name) {
this.name = name;
}
@Override
public void update(String news) {
System.out.println(name + " 收到新闻: " + news);
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
NewsPublisher newsPublisher = new NewsPublisher();
Observer subscriber1 = new Subscriber("Subscriber 1");
Observer subscriber2 = new Subscriber("Subscriber 2");
newsPublisher.registerObserver(subscriber1);
newsPublisher.registerObserver(subscriber2);
newsPublisher.setNews("新闻1发布了!");
newsPublisher.setNews("新闻2发布了!");
newsPublisher.deleteObserver(subscriber1);
newsPublisher.setNews("新闻3发布了!");
}
}
输出如下:
java/Spring 中的观察者模式有哪些?
Spring中的事件驱动模型见:Spring 中的设计模式详解 | JavaGuide(Java面试 + 学习指南)
Java中有几个内置的类和接口提供了观察者模式的实现,如 Observer
(观察者接口)和 Observable
(主题类)