上一篇地址:整理好了!2024年最常见 20 道设计模式面试题(二)-CSDN博客
五、适配器模式是如何工作的?请举例说明。
适配器模式(Adapter Pattern)是一种常用的设计模式,属于结构型模式之一。它主要用于解决两个不兼容接口之间的问题,使得原本因接口不兼容而不能一起工作的类可以协同工作。适配器模式通常包含以下几个角色:
- 目标(Target):定义客户端使用的特定领域相关的接口。
- 适配者(Adaptee):一个已经存在的类,需要适配。
- 适配器(Adapter):通过在内部包装一个Adaptee对象,把源接口转换成目标接口。
工作原理:
适配器模式的工作原理是创建一个中间层(适配器),这个中间层将不兼容的接口转换成客户端期望的接口。适配器模式让原本因接口不兼容而不能一起工作的类可以协同工作。
举例说明:
假设我们有一个第三方库,它提供了一个MediaPlayer
接口,该接口有一个play
方法,用于播放音频。但是,我们手头有一个旧的音频播放类OldAudioPlayer
,它有一个playAudio
方法,而不是play
方法。现在,我们想要使用OldAudioPlayer
来播放音频,但是它不符合MediaPlayer
接口的要求。
为了解决这个问题,我们可以创建一个适配器AudioPlayerAdapter
,它实现了MediaPlayer
接口,并在其内部持有一个OldAudioPlayer
的实例。当调用AudioPlayerAdapter
的play
方法时,它会调用内部OldAudioPlayer
的playAudio
方法,从而实现接口的适配。
// 目标接口
interface MediaPlayer {void play();
}// 旧的音频播放类
class OldAudioPlayer {public void playAudio() {System.out.println("Playing audio using OldAudioPlayer");}
}// 适配器类
class AudioPlayerAdapter implements MediaPlayer {private OldAudioPlayer oldAudioPlayer;public AudioPlayerAdapter(OldAudioPlayer oldAudioPlayer) {this.oldAudioPlayer = oldAudioPlayer;}@Overridepublic void play() {oldAudioPlayer.playAudio();}
}// 客户端代码
public class Client {public static void main(String[] args) {OldAudioPlayer oldAudioPlayer = new OldAudioPlayer();MediaPlayer mediaPlayer = new AudioPlayerAdapter(oldAudioPlayer);mediaPlayer.play(); // 通过适配器调用旧的播放方法}
}
在这个例子中,AudioPlayerAdapter
充当了适配器的角色,它使得OldAudioPlayer
能够以MediaPlayer
接口的形式被使用。这样,我们就可以在不修改原有代码的情况下,让旧的类与新的接口兼容。
六、什么是观察者模式?它在实际应用中有哪些用途?
观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象间的一种一对多的依赖关系,使得当一个对象状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。这种模式通常用于实现分布式事件处理系统。
观察者模式的主要角色:
- 主题(Subject):也称为被观察者,它维护一组观察者,提供注册、注销和通知观察者的方法。
- 观察者(Observer):定义了一个更新接口,用于在得到主题通知时更新自己。
- 具体主题(ConcreteSubject):实现抽象主题中的方法,维护当前状态,当状态发生改变时,通知所有观察者。
- 具体观察者(ConcreteObserver):实现观察者接口,存储与主题相关的状态,实现更新接口。
工作原理:
- 观察者模式中的主题维护一个观察者列表。
- 当主题的状态发生变化时,它会通知列表中的所有观察者。
- 观察者接收到通知后,会调用自己的更新方法,以响应主题状态的变化。
实际应用中的用途:
-
用户界面(UI)更新:在图形用户界面中,当模型数据发生变化时,界面需要相应地更新。观察者模式可以用于实现数据和视图之间的自动同步。
-
事件监听:在事件驱动的系统中,事件的发布者(主题)可以注册多个监听者(观察者),当事件发生时,所有监听者都会收到通知。
-
消息推送系统:在消息推送系统中,服务端(主题)可以向多个客户端(观察者)推送消息,当有新消息时,所有客户端都会收到通知。
-
股票市场监控:在股票交易系统中,股票价格的变化可以作为主题,而投资者、交易算法等可以作为观察者,当股票价格变动时,所有相关方都会得到通知。
-
网络通信:在网络通信中,服务器(主题)可以向多个客户端(观察者)发送数据更新,当数据发生变化时,所有客户端都会收到更新。
示例代码(Java):
// 观察者接口
interface Observer {void update(String message);
}// 主题接口
interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
}// 具体主题
class ConcreteSubject implements Subject {private List<Observer> observers = new ArrayList<>();private String state;public void registerObserver(Observer o) {observers.add(o);}public void removeObserver(Observer o) {int i = observers.indexOf(o);if (i >= 0) {observers.remove(i);}}public void notifyObservers() {for (Observer observer : observers) {observer.update(state);}}public void setState(String state) {this.state = state;notifyObservers();}public String getState() {return state;}
}// 具体观察者
class ConcreteObserver implements Observer {private ConcreteSubject subject;public ConcreteObserver(ConcreteSubject subject) {this.subject = subject;subject.registerObserver(this);}@Overridepublic void update(String message) {System.out.println("Observer: " + message);}
}// 客户端代码
public class Client {public static void main(String[] args) {ConcreteSubject subject = new ConcreteSubject();ConcreteObserver observer1 = new ConcreteObserver(subject);ConcreteObserver observer2 = new ConcreteObserver(subject);subject.setState("State1");subject.removeObserver(observer1);subject.setState("State2");}
}
在这个示例中,ConcreteSubject
是具体的主题,它维护了一个观察者列表,并在状态变化时通知所有观察者。ConcreteObserver
是具体观察者,实现了Observer
接口,当接收到通知时,会打印消息。客户端代码创建了主题和观察者,并演示了状态更新和观察者注册/注销的过程。