【设计模式】8、adapter 适配器模式

八、adapter 适配器模式

https://refactoringguru.cn/design-patterns/adapter

通常用于老旧系统, 或第三方系统, 提供一层适配器或插件, 做协议转换

PS: 如果开发新系统, 各层之间的解耦, 成为 bridge 桥接模式. 而如果是老系统则称为 adapter 适配器模式. 本质是一样的. 都是通过添加中间层实现的.

源码路径:godp/08adapter at master · datager/godp · GitHub

8.1 convert_lightning_to_usb

https://refactoringguru.cn/design-patterns/adapter/go/example

08adapter/081convert_lightning_to_usb
├── adapter.go
├── client.go
├── client_test.go
├── computer.go
└── readme.md

8.1.1 client_test.go

package _81convert_lightning_to_usb

import "testing"

/*
=== RUN   TestClient
insert lighting into computer
mac: insert into lightning port
insert lighting into computer
适配器: 将雷电口转换为USB口
windows: insert into usb port
--- PASS: TestClient (0.00s)
PASS
*/
func TestClient(t *testing.T) {
    mac := &mac{}
    windowsAdapter := &windowsAdapter{windowsComputer: &windows{}}

    c := &client{}
    c.InsertLightningIntoComputer(mac)
    c.InsertLightningIntoComputer(windowsAdapter)
}

8.1.2 client.go

package _81convert_lightning_to_usb

import "fmt"

type client struct {
}

func (c *client) InsertLightningIntoComputer(computer computer) {
    fmt.Println("insert lighting into computer")
    computer.InsertIntoLightningPort()
}

8.1.3 computer.go

package _81convert_lightning_to_usb

import "fmt"

type computer interface {
    InsertIntoLightningPort()
}

type mac struct{}

func (c *mac) InsertIntoLightningPort() {
    fmt.Println("mac: insert into lightning port")
}

type windows struct{}

func (c *windows) InsertIntoUSBPort() {
    // windows 只支持 usb 口, 不支持雷电口
    fmt.Println("windows: insert into usb port")
}

8.1.4 adapter.go

package _81convert_lightning_to_usb

import "fmt"

type windowsAdapter struct {
    windowsComputer *windows
}

func (a *windowsAdapter) InsertIntoLightningPort() {
    fmt.Println("适配器: 将雷电口转换为USB口")
    a.windowsComputer.InsertIntoUSBPort()
}

8.2 huawei_od_user_manager

参考 <设计模式之禅> 第 19 章

如果已有一个用户管理系统(如华为), 还希望对接第三方的外包管理系统(如od), 两个系统的接口, 数据肯定不一致.

既然是老系统, 时间紧任务重, 推倒重来肯定来不及, 所以可以写一个 adapter(适配器), 做协议转换.

adapter 就是俗称的包一层, 封装一层. 通常是相同的功能, 但协议不同, 需要加一个中间层做中转.

08adapter/082huawei_user_manager
├── huawei_user_manager.go
├── huawei_user_manager_test.go
├── od
│   ├── account.go
│   └── account_manager.go
├── od_adapter.go
├── readmd.md
└── user.go

8.2.1 huawei_user_manager_test.go

package _82huawei_user_manager

import (
	"fmt"
	"github.com/stretchr/testify/require"
	"godp/08adapter/082huawei_user_manager/od"
	"testing"
)

/*
=== RUN   TestHuaweiUserManagerGetAll
获取huawei本部员工
获取od员工
创建huawei od适配器
通过适配器, 获取huawei od员工
获取全部员工
--- PASS: TestHuaweiUserManagerGetAll (0.00s)
PASS
*/
func TestHuaweiUserManagerGetAll(t *testing.T) {
	fmt.Println("获取huawei本部员工")
	huaweiUsers := []user{
		&huaweiUser{id: "1", name: "CEO", departmentID: 0},
		&huaweiUser{id: "2", name: "CTO", departmentID: 0},
		&huaweiUser{id: "3", name: "CFO", departmentID: 0},
	}
	hum := NewHuaweiUserManager(huaweiUsers)
	us1 := hum.GetAll()

	fmt.Println("获取od员工")
	odAccounts := []od.Account{
		od.Account{ID: 881, Name: "CloudStaff1", PhoneNumber: "19900009999", CompanyToWorkFor: "huawei"},
		od.Account{ID: 882, Name: "CloudStaff2", PhoneNumber: "19911119999", CompanyToWorkFor: "huawei"},
		od.Account{ID: 883, Name: "AIStaff3", PhoneNumber: "19922229999", CompanyToWorkFor: "google"},
		od.Account{ID: 884, Name: "OSStaff4", PhoneNumber: "19933339999", CompanyToWorkFor: "microsoft"},
	}
	om := od.NewAccountManager(odAccounts)
	fmt.Println("创建huawei od适配器")
	odAdapter := NewHuaweiOdUserManagerAdapter(om)
	fmt.Println("通过适配器, 获取huawei od员工")
	us2 := odAdapter.GetAll()

	fmt.Println("获取全部员工")
	us := append(us1, us2...)
	require.Len(t, us, 3+2)

	ids := make([]string, 0)
	for _, u := range us {
		ids = append(ids, u.ID())
	}
	require.Contains(t, ids, "1")
	require.Contains(t, ids, "2")
	require.Contains(t, ids, "3")
	require.Contains(t, ids, "881")
	require.Contains(t, ids, "882")
	require.NotContains(t, ids, "883")
	require.NotContains(t, ids, "884")
}

8.2.2 huawei_user_manager.go

package _82huawei_user_manager

type userManager interface {
	GetAll() []user
}

type huaweiUserManager struct {
	users []user
}

func NewHuaweiUserManager(users []user) userManager {
	return &huaweiUserManager{users: users}
}

func (hum *huaweiUserManager) GetAll() []user {
	return hum.users
}

8.2.3 od_adapter.go

package _82huawei_user_manager

import (
	"godp/08adapter/082huawei_user_manager/od"
	"strconv"
)

const (
	huaweiCompanyName    = "huawei"
	huaweiODDepartmentID = 3
)

// huawei 的 od 员工适配器
type huaweiOdUserManagerAdapter struct {
	odManager od.AccountManager
}

func NewHuaweiOdUserManagerAdapter(odManager od.AccountManager) userManager {
	return &huaweiOdUserManagerAdapter{
		odManager: odManager,
	}
}

// GetAll 获取 huawei 的 od 员工
func (oma *huaweiOdUserManagerAdapter) GetAll() []user {
	huaweiUsers := make([]user, 0)
	odAccounts := oma.odManager.GetAll()
	for _, ac := range odAccounts {
		if ac.CompanyToWorkFor != huaweiCompanyName {
			continue
		}
		huaweiUsers = append(huaweiUsers, &huaweiUser{
			id:           strconv.Itoa(ac.ID),
			name:         ac.Name,
			departmentID: huaweiODDepartmentID,
		})
	}
	return huaweiUsers
}

8.2.4 od/account.go

package od

// Account 是 od 的 员工定义
type Account struct {
	ID               int
	Name             string
	PhoneNumber      string
	CompanyToWorkFor string // 为哪家公司工作, 如 "huawei"
}

8.2.5 od/account_manager.go

package od

type AccountManager struct {
	accounts []Account
}

func NewAccountManager(accounts []Account) AccountManager {
	return AccountManager{accounts: accounts}
}

func (am *AccountManager) GetAll() []Account {
	return am.accounts
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呆呆的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值