专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
OSC开源社区  ·  宇树王兴兴早年创业分享引围观 ·  2 天前  
OSC开源社区  ·  2024: 大模型背景下知识图谱的理性回归 ·  2 天前  
程序猿  ·  “我真的受够了Ubuntu!” ·  2 天前  
程序猿  ·  “未来 3 年内,Python 在 AI ... ·  3 天前  
程序员的那些事  ·  成人玩偶 + ... ·  3 天前  
51好读  ›  专栏  ›  SegmentFault思否

TypeScript 设计模式之适配器模式

SegmentFault思否  · 公众号  · 程序员  · 2020-01-18 10:00

正文

本文转载于 SegmentFault 社区专栏:全栈修仙之路

作者:semlinker





No.1

简介



在实际生活中,也存在适配器的使用场景,比如:港式插头转换器、电源适配器和 USB 转接口。而在软件工程中,适配器模式的作用是解决两个软件实体间的接口不兼容的问题。使用适配器模式之后,原本由于接口不兼容而不能工作的两个软件实体就可以一起工作。

图片来源 - https://meneguite.com/



No.2

优缺点



优点


•  将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,符合开闭原则。


缺点


过多地使用适配器,会让系统非常零乱,不易整体进行把握。



No.3

应用场景



系统需要使用现有的类,而这些类的接口不符合系统的需要。
想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。


No.4

模式结构



适配器模式包含以下角色:

Target:目标抽象类
Adapter:适配器类
Adaptee:适配者类
Client:客户类

适配器模式有对象适配器和类适配器两种实现,这里我们主要介绍对象适配器。

对象适配器:



No.5

实战



具体实现


定义 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
如你所见,适配器模式是一个非常有用的模式,对于任何开发人员来说,理解这种模式都是至关重要的。






请到「今天看啥」查看全文