TypeScript 设计模式之适配器模式

时间: 2019-12-13阅读: 311标签: 模式

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


二、优缺点

优点

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

缺点

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


三、应用场景

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


四、模式结构

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

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


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

2.广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入

链接: http://www.fly63.com/article/detial/7254

关闭

TypeScript 设计模式之单例模式

单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池、全局缓存、浏览器中的 window 对象等。单例模式用于保证一个类仅有一个实例,并提供一个访问它的全局访问点。

多属性、多分类MySQL模式设计

当数据同时具备多个属性/分类时,改如何设计表结构和查询?我这样写数据少了还好,多了根本没法查,效率太低了。恰好我以前做过类似的业务需求设计,所以就回复了这个问题。

vue-router的hash 模式和 history 模式

url 中带有#的便是 hash 模式,#后面是 hash 值,它的变化会触发 hashchange 这个事件。通过这个事件我们就可以知道 hash 值发生了哪些变化。

js模板模式

模板模式是抽象父类定义了子类需要重写的相关方法。 而这些方法,仍然是通过父类方法调用的。 根据描述,“模板”的思想体现在:父类定义的接口方法。

javascript 策略模式_理解js中的策略模式

javascript 策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。 策略模式利用组合,委托等技术和思想,有效的避免很多if条件语句,策略模式提供了开放-封闭原则,使代码更容易理解和扩展, 策略模式中的代码可以复用。

js设计模式:观察者和发布订阅模式

总是把这两个当作同一个模式,但其实是不太一样的,现在重温一下。观察者直接订阅目标,当目标触发事件时,通知观察者进行更新;发布订阅模式通过一个调度中心进行处理,使得订阅者和发布者分离开来

Js设计模式总汇

在程序设计中有很多实用的设计模式,而其中大部分语言的实现都是基于“类”。在JavaScript中并没有类这种概念,面向对象编程不是基于类,而是基于原型去面向对象编程,JS中的函数属于一等对象

如何自动加载网站的深色模式?

现在有一种新的趋势 - 把东西变黑。过去,你必须决定你的网站的风格(亮或暗)或者必须保存用户自己定义的主题风格。Safari 12.1 ( macOS 10.14.4自带) 增加了对检测系统颜色主题的支持

Js代理模式

所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网络连接、内存中的大对象、文件或其它昂贵或无法复制的资源。著名的代理模式例子为引用计数(英语:reference counting)指针对象。

前端设计模式:从js原始模式开始,去理解Js工厂模式和构造函数模式

工厂模式下的对象我们不能识别它的类型,由于typeof返回的都是object类型,不知道它是那个对象的实例。另外每次造人时都要创建一个独立的person的对象,会造成代码臃肿的情况。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!

文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全运营推广