TypeScript 设计模式之适配器模式
一、简介
在实际生活中,也存在适配器的使用场景,比如:港式插头转换器、电源适配器和 USB 转接口。而在软件工程中,适配器模式的作用是解决两个软件实体间的接口不兼容的问题。使用适配器模式之后,原本由于接口不兼容而不能工作的两个软件实体就可以一起工作。
(图片来源 – https://meneguite.com/)
二、优缺点
优点
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
- 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
- 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,符合开闭原则。
缺点
- 过多地使用适配器,会让系统非常零乱,不易整体进行把握。
三、应用场景
- 系统需要使用现有的类,而这些类的接口不符合系统的需要。
- 想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
四、模式结构
适配器模式包含以下角色:
- Target:目标抽象类
- Adapter:适配器类
- Adaptee:适配者类
- Client:客户类
适配器模式有对象适配器和类适配器两种实现,这里我们主要介绍对象适配器。
对象适配器:
五、实战
具体实现
定义 Target 接口
interface Target { request(): void; }
创建 Adaptee(适配者) 类
class Adaptee { public specificRequest(): void { console.log("specificRequest of Adaptee is being called"); } }
创建 Adapter(适配器)类
class Adapter implements Target { public request(): void { console.log("Adapter's request method is being called"); var adaptee: Adaptee = new Adaptee(); adaptee.specificRequest(); } }
使用示例
function show(): void { const adapter: Adapter = new Adapter(); adapter.request(); }
为了更好地理解适配器模式的作用,我们来举一个实际的应用示例。假设你现在拥有一个日志系统,该日志系统会将应用程序生成的所有信息保存到本地文件,具体如下:
interface Logger { info(message: string): Promise<void>; } class FileLogger implements Logger { public async info(message: string): Promise<void> { console.info(message); console.info('This Message was saved with FileLogger'); } }
基于上述的 FileLogger 类,我们就可以在 NotificationService 通知服务中使用它:
class NotificationService { protected logger: Logger; constructor (logger: Logger) { this.logger = logger; } public async send(message: string): Promise<void> { await this.logger.info(`Notification sended: ${message}`); } } (async () => { const fileLogger = new FileLogger(); const notificationService = new NotificationService(fileLogger); await notificationService.send('Hello Semlinker, To File'); })();
以上代码成功运行后会输出以下结果:
Notification sended: Hello Semlinker This Message was saved with FileLogger
但是现在我们需要使用一种新的方式来保存日志,因为随着应用的增长,我们需要将日志保存到云服务器上,而不再需要保存到磁盘中。因此我们需要使用另一种实现,比如:
interface CloudLogger { sendToServer(message: string, type: string): Promise<void>; } class AliLogger implements CloudLogger { public async sendToServer(message: string, type: string): Promise<void> { console.info(message); console.info('This Message was saved with AliLogger'); } }
但这时对于我们来说,要使用这个新类,我们就可能需要重构旧的代码以使用新的日志存储方式。为了避免重构代码,我们可以考虑使用适配器来解决这个问题。
class CloudLoggerAdapter implements Logger { protected cloudLogger: CloudLogger; constructor (cloudLogger: CloudLogger) { this.cloudLogger = cloudLogger; } public async info(message: string): Promise<void> { await this.cloudLogger.sendToServer(message, 'info'); } }
在定义好 CloudLoggerAdapter 适配器之后,我们就可以这样使用:
(async () => { const aliLogger = new AliLogger(); const cloudLoggerAdapter = new CloudLoggerAdapter(aliLogger); const notificationService = new NotificationService(cloudLoggerAdapter); await notificationService.send('Hello Kakuqo, To Cloud'); })();
以上代码成功运行后会输出以下结果:
Notification sended: Hello Kakuqo, To Cloud This Message was saved with AliLogger
如你所见,适配器模式是一个非常有用的模式,对于任何开发人员来说,理解这种模式都是至关重要的。
日志系统适配器完整示例
接口定义
interface Logger { info(message: string): Promise<void>; } interface CloudLogger { sendToServer(message: string, type: string): Promise<void>; }
日志实现类
class AliLogger implements CloudLogger { public async sendToServer(message: string, type: string): Promise<void> { console.info(message); console.info('This Message was saved with AliLogger'); } }
适配器
class CloudLoggerAdapter implements Logger { protected cloudLogger: CloudLogger; constructor (cloudLogger: CloudLogger) { this.cloudLogger = cloudLogger; } public async info(message: string): Promise<void> { await this.cloudLogger.sendToServer(message, 'info'); } }
通知服务类
class NotificationService { protected logger: Logger; constructor (logger: Logger) { this.logger = logger; } public async send(message: string): Promise<void> { await this.logger.info(`Notification sended: ${message}`); } }
使用示例
(async () => { const aliLogger = new AliLogger(); const cloudLoggerAdapter = new CloudLoggerAdapter(aliLogger); const notificationService = new NotificationService(cloudLoggerAdapter); await notificationService.send('Hello Kakuqo, To Cloud'); })();
六、参考资源
本人的全栈修仙之路订阅号,会定期分享 Angular、TypeScript、Node.js/Java 、Spring 相关文章,欢迎感兴趣的小伙伴订阅哈!
原文地址:https://segmentfault.com/a/1190000021562224
相关推荐
-
设计模式笔记(一):单例模式 javascript/jquery
2020-5-18
-
优雅的防止用户重复点击某个按钮 javascript/jquery
2019-6-29
-
Javascript操作DOM常用API总结 javascript/jquery
2017-5-4
-
简易页面回到顶部js代码 javascript/jquery
2020-5-26
-
前端面试题(十三) javascript/jquery
2020-6-12
-
梳理前端依赖管理 javascript/jquery
2020-5-27
-
一个TCP长连接设备管理后台工程(一) javascript/jquery
2020-6-16
-
如何在前端中使用protobuf(node篇) javascript/jquery
2020-5-27
-
异步编程之 async/await 函数 javascript/jquery
2019-10-2
-
vue组件开发——将弹层放置于 body 内,不受父级元素影响,在浏览器窗口改变或滚动时,依然跟随目标元素 javascript/jquery
2020-5-25