适配器模式
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 95 课,共 110 课。
适配器模式可以让不兼容的接口协同工作。它充当两个原本无法协作的类之间的桥梁,用客户端所需的新接口包装现有类。在将第三方库或旧代码集成到应用程序时,这种模式尤其有用。
假设你有一个处理 JSON 数据的系统,但需要集成一个只输出 XML 的组件。你不修改任何一个类,而是创建一个适配器,在它们之间进行转换:
// 系统需要的现有接口
abstract class JsonData {
String getJson();
}
// 接口不兼容的旧类
class XmlService {
String getXml() {
return '<data><name>John</name></data>';
}
}
// 适配器让 XmlService 与 JsonData 兼容
class XmlToJsonAdapter implements JsonData {
final XmlService _xmlService;
XmlToJsonAdapter(this._xmlService);
@override
String getJson() {
String xml = _xmlService.getXml();
// 将 XML 转换为 JSON(简化版)
return '{"name": "John"}';
}
}
void main() {
var xmlService = XmlService();
var adapter = XmlToJsonAdapter(xmlService);
print(adapter.getJson()); // {"name": "John"}
}XmlToJsonAdapter 封装了 XmlService,并实现了 JsonData 接口。客户端代码可以使用熟悉的 JsonData 接口,而无需知道数据最初来自 XML 源。适配器会在内部处理所有转换。
当你想使用现有的类,但它的接口与你需要的不匹配,或者需要创建一个可与接口不兼容的类协作的可复用类时,可以使用适配器模式。
挑战
简单让我们来构建一个媒体播放器适配器系统!想象一下,你有一个现代音频系统,它要求所有媒体源都通过标准接口提供音频,但你需要接入一台老式黑胶唱机,而它产生声音的方式完全不同。
你将创建两个文件来组织适配器模式的实现:
media_adapter.dart:这个文件包含接口和适配器类。定义一个抽象类AudioSource,这是现代系统所要求的接口。它应该包含一个方法String playAudio(),以字符串形式返回音频输出。然后创建一个代表旧式设备的VinylPlayer类,它有一个trackName字段,以及一个方法String spinRecord(),该方法返回*crackle* Playing vinyl: [trackName] *crackle*。最后,构建一个实现AudioSource并包装VinylPlayer的VinylAdapter。适配器的playAudio()方法应该调用黑胶唱机的spinRecord()方法并返回结果,从而连接不兼容的接口。main.dart:导入媒体适配器文件,并演示适配器如何让旧式黑胶唱机与依赖现代AudioSource接口的代码协同工作。创建一个曲目名称为Bohemian Rhapsody的VinylPlayer。然后创建一个包装这台黑胶唱机的VinylAdapter。将适配器存储在一个类型为AudioSource的变量中,以证明它符合预期的接口。在音频源上调用playAudio()并打印结果。
这种模式的妙处在于,你的主代码可以使用标准的 AudioSource 接口,而不必知道幕后实际工作的是一台旧式黑胶唱机!
预期输出:
*crackle* Playing vinyl: Bohemian Rhapsody *crackle*亲手试试
import 'media_adapter.dart';
void main() {
// TODO:创建一个 VinylPlayer,曲目名称为 "Bohemian Rhapsody"
// TODO:创建一个 VinylAdapter,封装该黑胶唱片播放器
// TODO:将适配器存入一个 AudioSource 类型的变量
// TODO:在你的音频源上调用 playAudio(),并打印结果
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器