1.概念
外观模式(Facade Pattern)是一种结构型设计模式,核心思想是:
- 统一入口:为复杂子系统提供简化接口
- 隐藏复杂性:封装内部多个模块/类的交互细节
- 降低耦合:客户端只需与外观类交互,不直接依赖子系统
2.在Android源码中的应用场景
2.1 Android ARouter(阿里巴巴开源的路由框架)在设计中运用了多种设计模式,以下是核心模式及其应用场景的详细分析:
- 应用场景:
ARouter入口类 - 实现:
提供统一的静态接口(如init(),build(),navigation()),隐藏内部复杂的路由初始化、拦截器调度、跨模块通信等逻辑。 - 代码体现:
// 用户只需调用简单接口
ARouter.getInstance().build("/user/profile").navigation();
2.2 Context 体系(核心外观模式实现
- 角色:
Context是抽象外观类,ContextImpl是具体外观类。 - 功能:封装了应用环境的核心操作(如启动组件、访问资源、系统服务等),隐藏了
ActivityManagerService、PackageManagerService等子系统的复杂性。 - 源码示例:
// ContextImpl.java
@Override
public void startActivity(Intent intent) {
// 委托给ActivityManagerService处理
mMainThread.getInstrumentation().execStartActivity(...);
}
@Override
public Object getSystemService(String name) {
// 返回子系统服务实例(如LayoutInflater、ConnectivityManager)
return SystemServiceRegistry.getSystemService(this, name);
}
开发者通过 Activity(继承自 Context)直接调用 startActivity() 等接口,无需关注 Binder 跨进程通信等底层细节
3.UML图
4.项目的例子和没用设计模式的对比
4.1 典型语音系统包含:
- 音频输入层:麦克风采集、降噪、VAD(语音活动检测)
- 核心引擎层:ASR(语音识别)、NLU(自然语言理解)、TTS(语音合成)
- 业务层:指令执行、对话管理、多轮交互
- 输出层:音频播放、设备控制
流程图:
4.2 不用外观l模式
// ===== 新增:意图表示类 =====
public class Intent {
private final String action;
private final String target;
private final String value;
public Intent(String action, String target, String value) {
this.action = action;
this.target = target;
this.value = value;
}
public String getAction() { return action; }
public String getTarget() { return target; }
public String getValue() { return value; }
@Override
public String toString() {
return action + ":" + target + "=" + value;
}
}
// ===== 新增:语音异常类 =====
public class VoiceException extends RuntimeException {
private final ErrorType type;
public VoiceException(ErrorType type, String message) {
super(message);
this.type = type;
}
public ErrorType getType() { return type; }
public enum ErrorType {
AUDIO_CAPTURE, // 音频采集错误
PROCESSING, // 处理错误
RECOGNITION, // 识别错误
UNDERSTANDING, // 理解错误
EXECUTION // 执行错误
}
}
// ===== 子系统组件 =====
public class AudioCapture {
public byte[] record(int durationMs) {
System.out.println("[AudioCapture] 录制音频中...时长: " + durationMs + "ms");
// 模拟10%概率出现采集失败
if (Math.random() > 0.9) {
throw new VoiceException(
VoiceException.ErrorType.AUDIO_CAPTURE,
"麦克风未就绪"
);
}
return new byte[1024]; // 模拟音频数据
}
}
public class NoiseReducer {
public byte[] process(byte[] rawAudio) {
System.out.println("[NoiseReducer] 降噪处理中...");
return rawAudio; // 返回处理后的音频
}
}
public class VADetector {
public byte[] removeSilence(byte[] audio) {
System.out.println("[VADetector] 静音段检测与切除...");
return audio;
}
}
public class SpeechRecognizer {
public String recognize(byte[] audio) {
System.out.println("[SpeechRecognizer] 语音识别中...");
// 模拟10%概率识别失败
if (Math.random() > 0.9) {
throw new VoiceException(
VoiceException.ErrorType.RECOGNITION,
"语音不清晰"
);
}
return "打开客厅的灯"; // 模拟识别结果
}
}
public class NLUProcessor {
public Intent parse(String text) {
System.out.println("[NLUProcessor] 自然语言理解中...");
// 简单的意图解析逻辑
if (text.contains("打开") && text.contains("灯")) {
String location = text.contains("客厅") ? "客厅" : "卧室";
return new Intent("light_control", location, "on");
} else if (text.contains("关闭")) {
String location = text.contains("客厅") ? "客厅" : "卧室";
return new Intent("light_control", location, "off");
} else if (text.contains("温度")) {
return new Intent("query", "temperature", "");
}
throw new VoiceException(
VoiceException.ErrorType.UNDERSTANDING,
"无法理解的指令: " + text
);
}
}
public class CommandExecutor {
public void execute(Intent intent) {
System.out.println("[CommandExecutor] 执行命令: " + intent);
// 模拟10%概率执行失败
if (Math.random() > 0.9) {
throw new VoiceException(
VoiceException.ErrorType.EXECUTION,
"设备未响应"
);
}
// 实际设备控制逻辑...
}
}
public class TTSEngine {
public byte[] synthesize(String text) {
System.out.println("[TTSEngine] 语音合成中: "" + text + """);
return text.getBytes();
}
}
public class AudioPlayer {
public void play(byte[] audio) {
System.out.println("[AudioPlayer] 播放音频...");
}
}
4.3 使用外观模式
// ===== 外观类 =====
public class VoiceSystemFacade {
private final AudioCapture capture;
private final NoiseReducer reducer;
private final VADetector vad;
private final SpeechRecognizer recognizer;
private final NLUProcessor nlu;
private final CommandExecutor executor;
private final TTSEngine tts;
private final AudioPlayer player;
public VoiceSystemFacade() {
// 初始化所有子系统组件
this.capture = new AudioCapture();
this.reducer = new NoiseReducer();
this.vad = new VADetector();
this.recognizer = new SpeechRecognizer();
this.nlu = new NLUProcessor();
this.executor = new CommandExecutor();
this.tts = new TTSEngine();
this.player = new AudioPlayer();
System.out.println("语音系统初始化完成");
}
// 核心简化接口
public void processVoiceCommand(int durationMs) {
try {
// 1. 音频采集与处理
byte[] processedAudio = processAudio(durationMs);
// 2. 语音识别与理解
Intent intent = recognizeAndParse(processedAudio);
// 3. 执行命令
executeCommand(intent);
// 4. 语音反馈
provideFeedback("已执行命令: " + intent.getAction());
} catch (VoiceException e) {
handleError(e);
}
}
// 语音识别专用接口
public String recognizeSpeech(int durationMs) {
byte[] audio = processAudio(durationMs);
return recognizer.recognize(audio);
}
// 语音播报接口
public void speak(String text) {
byte[] audio = tts.synthesize(text);
player.play(audio);
}
// ===== 私有方法封装实现细节 =====
private byte[] processAudio(int durationMs) {
byte[] raw = capture.record(durationMs);
byte[] clean = reducer.process(raw);
return vad.removeSilence(clean);
}
private Intent recognizeAndParse(byte[] audio) {
String text = recognizer.recognize(audio);
return nlu.parse(text);
}
private void executeCommand(Intent intent) {
executor.execute(intent);
}
private void provideFeedback(String message) {
byte[] audio = tts.synthesize(message);
player.play(audio);
}
private void handleError(VoiceException e) {
String errorMsg = "语音指令处理失败: " + e.getMessage();
System.err.println(errorMsg);
speak(errorMsg);
}
}
调用
// ===== 客户端调用 =====
public class SmartHomeApp {
public void processVoiceCommand() {
// 1. 音频采集
AudioCapture capture = new AudioCapture();
byte[] rawAudio = capture.record(3000);
// 2. 音频预处理
NoiseReducer reducer = new NoiseReducer();
byte[] cleanAudio = reducer.process(rawAudio);
VADetector vad = new VADetector();
byte[] finalAudio = vad.removeSilence(cleanAudio);
// 3. 语音识别
SpeechRecognizer recognizer = new SpeechRecognizer();
String text = recognizer.recognize(finalAudio);
// 4. 语义理解
NLUProcessor nlu = new NLUProcessor();
Intent intent = nlu.parse(text);
// 5. 执行命令
CommandExecutor executor = new CommandExecutor();
executor.execute(intent);
// 6. 语音反馈
TTSEngine tts = new TTSEngine();
byte[] responseAudio = tts.synthesize("已为您打开客厅的灯");
AudioPlayer player = new AudioPlayer();
player.play(responseAudio);
}
public static void processVoiceCommandByFaced() {
// 单行代码完成整个语音流程
voiceSystem.processVoiceCommand(3000);
}
private static VoiceSystemFacade voiceSystem;
public static void announceTime() {
voiceSystem.speak("当前时间是 ");
}
public static void main(String[] args) {
System.out.println("------------------main-------------------");
SmartHomeApp app = new SmartHomeApp();
app.processVoiceCommand();
voiceSystem = new VoiceSystemFacade();
announceTime();
processVoiceCommandByFaced();
}
}
gradle的配置
plugins {
id 'java-library'
}
// ==== 添加以下配置 ====
task runSmartHomeApp(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
mainClass = "com.example.design.face.SmartHomeApp" // 替换为你的完整类名
dependsOn 'classes'
}
afterEvaluate {
// 确保在构建后运行
tasks.named('runSmartHomeApp') {
it.mustRunAfter 'build'
}
}
详细的打印日志:
[VoiceSystem] 语音系统初始化完成
测试场景1: 正常指令
===== 开始语音指令处理 =====
[AudioCapture] 录制音频中...时长: 2000ms
[NoiseReducer] 降噪处理中...
[VADetector] 静音段检测与切除...
[SpeechRecognizer] 语音识别中...
[NLUProcessor] 自然语言理解中...
[CommandExecutor] 执行命令: light_control:客厅=on
[TTSEngine] 语音合成中: "已执行命令: light_control:客厅=on"
[AudioPlayer] 播放音频...
===== 语音指令处理完成 =====
测试场景2: 仅语音识别
[AudioCapture] 录制音频中...时长: 1500ms
[NoiseReducer] 降噪处理中...
[VADetector] 静音段检测与切除...
[SpeechRecognizer] 语音识别中...
识别结果: 打开客厅的灯
测试场景3: 异常处理演示
===== 开始语音指令处理 =====
[AudioCapture] 录制音频中...时长: 1000ms
[错误] 语音指令处理失败: 麦克风未就绪
[TTSEngine] 语音合成中: "麦克风故障,请检查设备"
[AudioPlayer] 播放音频...
===== 开始语音指令处理 =====
[AudioCapture] 录制音频中...时长: 1000ms
[NoiseReducer] 降噪处理中...
[VADetector] 静音段检测与切除...
[SpeechRecognizer] 语音识别中...
[错误] 语音指令处理失败: 语音不清晰
[TTSEngine] 语音合成中: "抱歉,没有听清楚,请再说一次"
[AudioPlayer] 播放音频...
===== 开始语音指令处理 =====
[AudioCapture] 录制音频中...时长: 1000ms
[NoiseReducer] 降噪处理中...
[VADetector] 静音段检测与切除...
[SpeechRecognizer] 语音识别中...
[NLUProcessor] 自然语言理解中...
[CommandExecutor] 执行命令: light_control:客厅=on
[TTSEngine] 语音合成中: "已执行命令: light_control:客厅=on"
[AudioPlayer] 播放音频...
===== 语音指令处理完成 =====
测试场景4: 直接播报
[TTSEngine] 语音合成中: "现在时间是下午三点整"
[AudioPlayer] 播放音频...
四、外观模式在语音系统中的核心优势
-
简化复杂系统入口
// 使用前 capture.record() → reducer.process() → vad.removeSilence() → ... // 使用后 voiceSystem.processVoiceCommand(3000); -
统一错误处理机制
private void handleError(VoiceException e) { // 统一记录日志 logger.error("Voice processing failed", e); // 根据错误类型播放不同提示 if(e.getType() == ErrorType.NO_AUDIO) { speak("未检测到语音输入"); } else if(e.getType() == ErrorType.RECOGNITION_FAILED) { speak("未能识别您的指令"); } }3. 灵活替换底层实现
public VoiceSystemFacade(RecognitionEngine engine) { // 可注入不同的识别引擎 this.recognizer = new SpeechRecognizer(engine); }
5.优点
- ✅ 简化客户端调用复杂度
- ✅ 提高代码可维护性(修改内部不影响客户端)
- ✅ 作为系统边界,明确职责划分
- ✅ 特别适合重构遗留复杂系统
6.和别的设计模式的区别
门面模式的核心价值在于解决复杂系统易用性问题,这是其他模式无法替代的:
-
与适配器的区别:
- 适配器解决
接口不匹配,门面解决接口太复杂
- 适配器解决
-
与中介者的区别:
- 中介者关注
对象间通信解耦,门面关注简化客户端调用
- 中介者关注
-
与代理的区别:
- 代理控制
单个对象的访问,门面封装多个对象的协作
- 代理控制
demo的地址: github.com/pengcaihua1…