13

TypeScript 设计模式之适配器模式

 4 years ago
source link: https://semlinker.com/ts-adapter-pattern/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

VRJZruF.jpg!web

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

二、优缺点

优点

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

缺点

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

三、应用场景

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

四、模式结构

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

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

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

对象适配器:

FzAb6fN.png!web

五、实战

具体实现

定义 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技术栈最新文章。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK