返回

贴近式设计模式:用Go语言剖析适配器模式及其实际案例

后端

在本文中,我们将深入探讨为什么写“适配器”模式呢?这一篇关于适配器模式的文章,因为它包含了丰富的场景和实务案例,诸如“监听”平台事件适配数据,调用第三方 接口适配外部数据。最重要的是,我们将通过 Go 语言来剖析适配器模式,并提供详细的实例和案例,让您深入理解如何将抽象和具体的类型一起工作。所以,如果您对设计模式和适配器模式感兴趣,就请继续阅读吧!

1、适配器模式,它是啥?

适配器模式是一种设计模式,它允许两个本来不能兼容的类协同工作。它可以把一个类的借口装扮成别的类的借口,使得本来的两个不能一起工作的类可以一起工作。适配器模式还有助于设计出更松散耦合的系统。

2、适配器模式的优缺点

优 点:

  • 可使本来不能在一起工作的两个系统协同工作。
  • 有助于设计出更松散耦合的系统。
  • 实现了类的适配,便于扩展。

缺 点:

  • 系统设计变得复杂,使得系统更难理解。
  • 需要预先设计好支持的类型。
  • 实现代码比较困难,可能会产生很多适配器。

3、适配器模式的实战案例

场景 1:监听平台事件适配数据

以下代码片段中,EventAdapterEvent 的借口装扮成 Message 的借口,使得本来不能一起工作的 EventMessage 可以一起工作。

// EventAdapter 实现了Message借口
type EventAdapter struct {
	Event event.Event
}

func (adapter *EventAdapter) Handle() {
	adapter.Event.DoSomething()
}

// MessageHandler 通过adapter来适配Event
type MessageHandler struct {
	Adapter EventAdapter
}

func (handler *MessageHandler) Handle() {
	handler.Adapter.Handle()
}

// Event 是被适配者
type Event struct {
	DoSomething func()
}

func NewEvent(doSomething func()) Event {
	return Event{DoSomething: doSomething}
}

func NewEventAdapter(event Event) EventAdapter {
	return EventAdapter{Event: event}
}

func NewMessageHandler(adapter EventAdapter) MessageHandler {
	return MessageHandler{Adapter: adapter}
}

// 消息处理函数
func ProcessMessage(handler MessageHandler) {
	handler.Handle()
}

func main() {
	event := NewEvent(func() {
		fmt.Println("事件被处理了")
	})
	adapter := NewEventAdapter(event)
	handler := NewMessageHandler(adapter)
	ProcessMessage(handler)
}

场景 2:调用第三方 接口适配外部数据

以下代码片段中,OldSystemNewSystem 的借口不一样,所以不能一起工作。但是,我们可以通过 Adapter 来适配,使得 OldSystemNewSystem 可以一起工作。

// OldSystem 是被适配者
type OldSystem struct {
	Name string
}

func (system *OldSystem) PrintName() {
	fmt.Println(system.Name)
}

// NewSystem 实现了OldSystem的借口
type NewSystem struct {
	Name string
}

func (system *NewSystem) PrintName() {
	fmt.Println(system.Name)
}

// ObjectAdapter 对象适配器
type ObjectAdapter struct {
	OldSystem OldSystem
}

func (adapter *ObjectAdapter) PrintName() {
	adapter.OldSystem.PrintName()
}

// Client 客户端
type Client struct {
	System System
}

func (client *Client) PrintName() {
	client.System.PrintName()
}

// 创建对象适配器
func NewObjectAdapter(system OldSystem) ObjectAdapter {
	return ObjectAdapter{OldSystem: system}
}

// 创建客户端
func NewClient(system System) Client {
	return Client{System: system}
}

func main() {
	oldSystem := NewOldSystem("老系统")
	adapter := NewObjectAdapter(oldSystem)
	client := NewClient(adapter)
	client.PrintName()

	newSystem := NewNewSystem("新系统")
	client.System = newSystem
	client.PrintName()
}

4、适配器模式的扩展

适配器模式有以下几种扩展:

  • 类适配器:这种适配器模式使用继承来适配两个不相容的类。
  • 对象适配器:这种适配器模式使用组合来适配两个不相容的类。
  • 接口适配器:这种适配器模式使用实现来适配两个不相容的类。

5、适配器模式的使用场景

  • 当我们需要将一个类适配到另一个类时,可以使用适配器模式。
  • 当我们需要在两个类之间进行转换时,可以使用适配器模式。
  • 当我们需要将两个类结合在一起时,可以使用适配器模式。

6、适配器模式与其他设计模式的关系

  • 适配器模式与代理模式相似,但代理模式侧重于为一个对象提供一个替代者,而适配器模式侧重于将两个不相容的类结合在一起。
  • 适配器模式与门面模式相似,但门面模式侧重于为一组相关类提供一个统一的借口,而适配器模式侧重于将两个不相容的类结合在一起。
  • 适配器模式与桥接模式相似,但桥接模式侧重于将抽象和具体的类结合在一起,而适配器模式侧重于将两个不相容的类结合在一起。

7、适配器模式的代码范例

以下代码片段是适配器模式的代码范例:

// TargetInterface 目标借口
type TargetInterface interface {
	Request() string
}

// TargetConcreteClass 具体的实现类
type TargetConcreteClass struct {
	TargetInterface
}

// adaptee.h 被适配者
type adaptee struct {
	SpecificRequest() string
}

// adapter.h 适配者
type adapter struct {
	adaptee
}

int main() {
    adaptee adaptee1;
    adapter adapter1;
    adapter1.adaptee = adaptee1;
    adapter1.Request(); // output: adaptee1's SpecificRequest
    
    adaptee adaptee2;
    adapter adapter2;
    adapter2.adaptee = adaptee2;
    adapter2.Request(); // output: adaptee2's SpecificRequest
    
    return 0;
}

8、适配器模式的优缺点

优 点:

  • 可使本来不能在一起工作的两个系统协同工作。
  • 有助于设计出更松散耦合的系统。
  • 实现了类的适配,便于扩展。

缺 点:

  • 系统设计变得复杂,使得系统更难理解。
  • 需要预先设计好支持的类型。
  • 实现代码比较困难,可能会产生很多适配器。

9、适配器模式的适用场景

适配器模式适用于以下场景:

  • 当我们需要将一个类适配到另一个类时。
  • 当我们需要在两个类之间进行转换时。
  • 当我们需要将两个类结合在一起时。