适配器模式学习笔记
适配器模式
定义:将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。
相关参与者 | 需求表达 |
---|---|
客户端 | 我需要调用实现了 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
方法。
什么时候使用适配器模式?当你想要修改一个已经投产的接口时,这时不要慌,也不要去改接口,增加一个适配器类就可以了。
适配器有两种
- 类适配器,通过类间继承来实现,上述例子就是一个典型的类适配器的运用。
- 对象适配器,通过对象的组合来实现。有些编程语言不支持继承的话,就只能通过组合的方式来实现适配器。
比如 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
是派生类。派生类通过在结构体中嵌入基类的实例来实现组合。这样派生类就可以访问基类的字段和方法。在派生类的方法中,可以通过派生类实例的基类字段来调用基类的方法。