适配器模式学习笔记

适配器模式学习笔记

适配器模式

定义:将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。

相关参与者需求表达
客户端我需要调用实现了 A 接口的类
服务方我只能提供实现了 B 接口的类
适配器我继承服务方提供的类,同时实现 A 接口,这样客户端就能轻松调用了

Typescript 举个例子:

// 邮件发送库接口
interface IEmailSender {
  send(to: string, subject: string, body: string): void;
}

// 邮件客户端
class EmailClient {
  private emailSender: IEmailSender;

  constructor(emailSender: IEmailSender) {
    this.emailSender = emailSender;
  }

  send(to: string, subject: string, body: string) {
    this.emailSender.send(to, subject, body);
  }
}

// 第三方邮件发送库
class MailgunSender {
  sendEmail(to: string, subject: string, body: string) {
    console.log(`Sending email to ${to}`);
    console.log(`Subject: ${subject}`);
    console.log(`Body: ${body}`);
    // 实际的邮件发送逻辑
  }
}

// 适配器类
class MailgunSenderAdapter extends MailgunSender implements IEmailSender {
  send(to: string, subject: string, body: string) {
    this.sendEmail(to, subject, body);
  }
}

// 使用适配器
const adapter = new MailgunSenderAdapter();
const client = new EmailClient(adapter);
client.send('example@example.com', 'Hello', 'This is a test email');

EmailClient 类是不能直接使用 MailgunSender 实例的,因为接口不符。但是通过 MailgunSenderAdapter 包装能做到间接调用了 MailgunSender 中的 sendEmail 方法。

什么时候使用适配器模式?当你想要修改一个已经投产的接口时,这时不要慌,也不要去改接口,增加一个适配器类就可以了。

适配器有两种

  1. 类适配器,通过类间继承来实现,上述例子就是一个典型的类适配器的运用。
  2. 对象适配器,通过对象的组合来实现。有些编程语言不支持继承的话,就只能通过组合的方式来实现适配器。

比如 Golang , 没有继承语法的情况下如何实现适配器呢?

package main

import "fmt"

// 邮件发送库接口
type IEmailSender interface {
	Send(to, subject, body string)
}

// 邮件客户端
type EmailClient struct {
	emailSender IEmailSender
}
func (ec *EmailClient) Send(to, subject, body string) {
	ec.emailSender.Send(to, subject, body)
}

// 第三方邮件发送库
type MailgunSender struct{}
func (e *MailgunSender) SendEmail(to, subject, body string) {
	fmt.Printf("Sending email to %s\n", to)
	fmt.Printf("Subject: %s\n", subject)
	fmt.Printf("Body: %s\n", body)
	// 实际的邮件发送逻辑
}

// 适配器类
type MailgunSenderAdapter struct {
	emailSender *MailgunSender
}
func (a *MailgunSenderAdapter) Send(to, subject, body string) {
	a.emailSender.SendEmail(to, subject, body)
}

func main() {
  // 使用适配器
	emailSender := &MailgunSender{}
	emailSenderAdapter := &MailgunSenderAdapter{emailSender:emailSender}
    emailClient :=  &EmailClient{emailSender: emailSenderAdapter}
	emailClient.Send("example@example.com", "Hello", "This is a test email")
}

在Go语言中,并没有像其他面向对象语言(如Typescript、Java、C#)中的继承机制。Go语言采用了一种组合的方式来实现类似继承的功能。

在上面的代码中,MailgunSender是基类,MailgunSenderAdapter是派生类。派生类通过在结构体中嵌入基类的实例来实现组合。这样派生类就可以访问基类的字段和方法。在派生类的方法中,可以通过派生类实例的基类字段来调用基类的方法。