观察者模式:一对多依赖,主题状态变更自动通知所有观察者,实现解耦。
1.概念
观察者模式(Observer Pattern) 是一种行为型设计模式,定义对象间一种 一对多的依赖关系,当一个对象(被观察者/Subject)状态改变时,所有依赖它的对象(观察者/Observer)都会自动收到通知并更新。核心角色:
- Subject(主题) :维护观察者列表,提供注册/注销接口,负责通知观察者
- Observer(观察者) :定义更新接口,接收状态变更通知
- ConcreteSubject & ConcreteObserver:具体实现类
2.在Android源码中的应用场景
- LiveData
LiveData
是被观察者,Activity/Fragment 作为观察者通过observe()
注册,数据变化时自动更新 UI。 - View 的事件监听
View.setOnClickListener()
本质是观察者模式(View 是 Subject,OnClickListener 是 Observer)。 - RecyclerView.Adapter
Adapter
是被观察者,调用notifyDataSetChanged()
通知 RecyclerView(观察者)刷新视图。 - BroadcastReceiver
系统广播中心是被观察者,接收器(BroadcastReceiver)作为观察者监听广播。
3.UML图
4.语音项目的例子和没用设计模式的对比
场景:语音识别模块识别到指令后,需同时更新 UI、保存日志、控制设备。
4.1 未使用观察者模式(耦合代码)
public class CloudService {
public static void syncCommand(String command) {
}
}
public class DatabaseEngine {
// 使用 SQLiteOpenHelper 获取数据库实例
private final SQLiteDatabase db;
private final DatabaseHelper dbHelper; // 自定义的 SQLiteOpenHelper
public DatabaseEngine(Context context) {
// 正确初始化:通过 DatabaseHelper 获取数据库实例
this.dbHelper = new DatabaseHelper(context);
this.db = dbHelper.getWritableDatabase();
}
public void logVoiceCommand(String command) {
ContentValues values = new ContentValues();
values.put("command", command);
values.put("timestamp", System.currentTimeMillis());
try {
// 插入数据到 voice_logs 表
db.insert("voice_logs", null, values);
} catch (Exception e) {
Log.e("DatabaseEngine", "保存失败: " + e.getMessage());
}
}
// 关闭数据库连接(可选)
public void close() {
if (db != null && db.isOpen()) {
db.close();
}
if (dbHelper != null) {
dbHelper.close();
}
}
}
public class DatabaseHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "voice_commands.db";
private static final int DATABASE_VERSION = 1;
// 表结构定义
private static final String CREATE_TABLE_VOICE_LOGS =
"CREATE TABLE voice_logs (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
"command TEXT NOT NULL," +
"timestamp INTEGER NOT NULL)";
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// 创建表
db.execSQL(CREATE_TABLE_VOICE_LOGS);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 简单处理:删除旧表,创建新表
db.execSQL("DROP TABLE IF EXISTS voice_logs");
onCreate(db);
}
}
public class SmartDeviceController {
// 模拟物联网设备控制
public void turnOnLights() {
Log.i("DeviceCtrl", "执行:打开灯光");
// 实际硬件控制代码(如MQTT/HTTP请求)
}
public void turnOffLights() {
Log.i("DeviceCtrl", "执行:关闭灯光");
}
// 扩展方法示例
public void increaseTemperature() {
Log.i("DeviceCtrl", "温度升高1℃");
}
}
public class UIUpdater {
private final TextView commandTextView; // Android视图组件
public UIUpdater(TextView textView) {
this.commandTextView = textView;
}
public void updateCommandText(String text) {
// 确保在主线程更新UI
commandTextView.post(() -> {
commandTextView.setText(text);
commandTextView.setTextColor(Color.GREEN);
});
}
}
public class VoiceRecognizer {
// 1. UI更新类(替换TextView)
private UIUpdater uiUpdater;
// 2. 数据库引擎类(替换DatabaseHelper)
private DatabaseEngine databaseEngine;
// 3. 设备控制器(保留原类)
private SmartDeviceController deviceController;
public VoiceRecognizer(
UIUpdater uiUpdater,
DatabaseEngine databaseEngine,
SmartDeviceController deviceController
) {
this.uiUpdater = uiUpdater;
this.databaseEngine = databaseEngine;
this.deviceController = deviceController;
}
// 语音识别回调
public void onVoiceCommandReceived(String command) {
// 1. 更新UI
uiUpdater.updateCommandText("识别结果: " + command);
// 2. 保存到数据库
databaseEngine.logVoiceCommand(command);
// 3. 控制设备
if ("打开灯光".equals(command)) {
deviceController.turnOnLights();
} else if ("关闭灯光".equals(command)) {
deviceController.turnOffLights();
}
// 4. 新功能:网络同步(紧耦合)
new Thread(() -> CloudService.syncCommand(command)).start();
}
}
4.2 使用观察者模式
// 云端同步观察者
public class CloudSyncerObs implements VoiceObserverObs {
@Override
public void onVoiceCommandReceived(String command) {
new Thread(() -> {
Log.i("CloudSyncerObs", "同步命令: " + command);
// 实际网络请求代码...
}).start();
}
}
// 数据库日志观察者
public class DatabaseLoggerObs implements VoiceObserverObs {
private final DatabaseEngine dbEngine; // 未改名
public DatabaseLoggerObs(Context context) {
this.dbEngine = new DatabaseEngine(context);
}
@Override
public void onVoiceCommandReceived(String command) {
dbEngine.logVoiceCommand(command);
}
public void closeDatabase() {
dbEngine.close();
}
}
// 设备控制观察者
public class DeviceControllerObs implements VoiceObserverObs {
private final SmartDeviceController device; // 未改名
public DeviceControllerObs() {
this.device = new SmartDeviceController();
}
@Override
public void onVoiceCommandReceived(String command) {
if ("打开灯光".equals(command)) {
device.turnOnLights();
} else if ("关闭灯光".equals(command)) {
device.turnOffLights();
}
}
}
// UI更新观察者
public class UiUpdaterObs implements VoiceObserverObs {
private final TextView commandTextView;
public UiUpdaterObs(TextView textView) {
this.commandTextView = textView;
}
@Override
public void onVoiceCommandReceived(String command) {
commandTextView.post(() -> {
commandTextView.setText("命令: " + command);
commandTextView.setTextColor(Color.GREEN);
});
}
}
public interface VoiceObserverObs {
void onVoiceCommandReceived(String command);
}
// 2. 被观察者(主题)
public class VoiceRecognizerObs {
private final List<VoiceObserverObs> observers = new ArrayList<>();
public void registerObserver(VoiceObserverObs observer) {
if (!observers.contains(observer)) {
observers.add(observer);
}
}
public void unregisterObserver(VoiceObserverObs observer) {
observers.remove(observer);
}
private void notifyObservers(String command) {
for (VoiceObserverObs observer : observers) {
observer.onVoiceCommandReceived(command);
}
}
// 语音识别回调
public void onVoiceCommandReceived(String command) {
Log.i("VoiceRecognizerObs", "识别命令: " + command);
notifyObservers(command);
}
}
具体的调用逻辑:
public class MainActivity extends AppCompatActivity {
private VoiceRecognizerObs voiceRecognizer;
private DatabaseLoggerObs dbLogger;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
TextView resultView = findViewById(R.id.tv_page_name);
// 创建被观察者(Obs版本)
voiceRecognizer = new VoiceRecognizerObs();
// 创建并注册观察者(Obs版本)
voiceRecognizer.registerObserver(new UiUpdaterObs(resultView));
voiceRecognizer.registerObserver(new DatabaseLoggerObs(this));
voiceRecognizer.registerObserver(new DeviceControllerObs());
voiceRecognizer.registerObserver(new CloudSyncerObs());
// 模拟语音识别
simulateVoiceRecognition();
}
private void simulateVoiceRecognition() {
new Handler().postDelayed(() -> {
// 发送命令1
voiceRecognizer.onVoiceCommandReceived("打开灯光");
// 2秒后发送命令2
new Handler().postDelayed(() -> {
voiceRecognizer.onVoiceCommandReceived("关闭灯光");
}, 2000);
}, 1000);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 清理资源
if (dbLogger != null) {
dbLogger.closeDatabase();
}
}
}
4.3 架构图
4.4.数据流向图
分析如下的区别.使用观察者和没有使用观察者的区别!
// UI更新观察者
public class UiUpdaterObs implements VoiceObserverObs {
private final TextView commandTextView;
public UiUpdaterObs(TextView textView) {
this.commandTextView = textView;
}
@Override
public void onVoiceCommandReceived(String command) {
commandTextView.post(() -> {
commandTextView.setText("命令: " + command);
commandTextView.setTextColor(Color.GREEN);
});
}
}
public class UIUpdater {
private final TextView commandTextView; // Android视图组件
public UIUpdater(TextView textView) {
this.commandTextView = textView;
}
public void updateCommandText(String text) {
// 确保在主线程更新UI
commandTextView.post(() -> {
commandTextView.setText(text);
commandTextView.setTextColor(Color.GREEN);
});
}
}
调用的区别
**观察者模式中的使用**:
// 注册观察者
voiceRecognizerObs.registerObserver(new UiUpdaterObs(textView));
// 语音识别回调自动触发UI更新
voiceRecognizerObs.onVoiceCommandReceived("打开灯光");
**非观察者模式中的使用**:
// 初始化工具类
UIUpdater uiUpdater = new UIUpdater(textView);
// 需要显式调用
voiceRecognizer.onVoiceCommandReceived("打开灯光", () -> {
uiUpdater.updateCommandText("命令: 打开灯光");
});
最终结论:
- 选择
UiUpdaterObs
(被动调用,收到外面的事件),当您需要构建事件驱动的响应式架构,特别是在复杂系统中处理状态变化通知 - 选择
UIUpdater(主动调用,外面手动调用这个方法)
当您需要简单通用的UI更新工具,不涉及复杂的事件传递机制 - 在大型项目中,推荐使用观察者模式变体以获得更好的可维护性和扩展性
5.优点
- 解耦:被观察者与观察者松耦合,互不依赖具体实现
- 动态扩展:可运行时添加/删除观察者(如注册/注销广播)
- 符合开闭原则:新增观察者无需修改被观察者代码
- 事件驱动:适用于异步场景(如网络回调、传感器数据)
- 数据一致性:确保所有依赖对象状态同步更新
6.和相似的设计模式的区别
模式 | 观察者模式 | 发布-订阅模式 | 中介者模式 |
---|---|---|---|
耦合度 | 观察者与被观察者直接交互 | 通过消息中心解耦 | 对象通过中介者间接交互 |
通信方向 | 单向(Subject → Observer) | 双向(Pub/Sub 可互发消息) | 多向(中介协调所有对象) |
实时性 | 实时同步通知 | 可异步(消息队列) | 实时 |
Android 案例 | LiveData、OnClickListener | EventBus、RxJava | Fragment 间通过 Activity 通信 |
关键区别:
-
观察者 vs 发布-订阅:
观察者模式是 直接调用(如listener.onClick()
),发布-订阅通过 中间代理(如 EventBus 的post(event)
)。 -
观察者 vs 中介者:
观察者处理 一对多通知,中介者解决 多对象复杂交互(如多个 Fragment 状态同步)。
总结:
观察者模式:一对多依赖,主题状态变更自动通知所有观察者,实现解耦。