前言
Bridge模式核心在于将抽象部分与实现部分分离,使他们都可以独立变化。简单来说就是向一座桥一样,左边和有边都有可能变化,但是他们之间通过一座桥相连接(有些抽象下面还是从实际情况出发)。
问题
在一个电商平台里,有不同类型的商品(比如电子产品、服装、图书等)需要展示商品详情信息给用户,同时用户购买商品时可以选择不同的支付方式(如微信支付、支付宝支付、银行卡支付等)。我们希望能够灵活地添加新的商品类型或者新的支付方式,而不影响现有的代码结构,这时候桥接模式就能派上用场了。
解决方案
首先定义抽象化部分(商品展示抽象接口):
// GoodsDisplay 商品展示抽象接口,定义了展示商品详情的方法
type GoodsDisplay interface {
ShowDetails() string
}
这个接口规定了商品需要实现展示详情的功能,具体怎么展示由不同类型的商品去实现。
接着定义实现化部分(支付方式接口):
// PaymentMethod 支付方式接口,定义了执行支付的抽象方法
type PaymentMethod interface {
Pay(amount float64) bool
}
该接口抽象出了支付操作,不管是哪种具体的支付手段,都需要实现这个支付的基本逻辑,即传入支付金额,然后返回支付是否成功的结果。
然后是具体实现化部分(具体支付方式的实现)
// WeChatPayment 微信支付结构体,实现了PaymentMethod接口
type WeChatPayment struct{}
func (w WeChatPayment) Pay(amount float64) bool {
// 这里模拟微信支付的逻辑,实际中会调用微信支付的相关API
println("使用微信支付,金额:", amount)
return true
}
// AlipayPayment 支付宝支付结构体,实现了PaymentMethod接口
type AlipayPayment struct{}
func (a AlipayPayment) Pay(amount float64) bool {
// 模拟支付宝支付逻辑,实际会涉及支付宝接口调用等
println("使用支付宝支付,金额:", amount)
return true
}
// BankCardPayment 银行卡支付结构体,实现了PaymentMethod接口
type BankCardPayment struct{}
func (b BankCardPayment) Pay(amount float64) bool {
// 模拟银行卡支付的一些验证、支付操作等
println("使用银行卡支付,金额:", amount)
return true
}
以上分别实现了微信支付、支付宝支付和银行卡支付三种具体的支付方式,它们都遵循 PaymentMethod
接口定义的 Pay
方法规范,完成各自的支付逻辑模拟(实际应用中会对接相应支付平台的真实接口)。
再来看具体抽象化部分(具体商品类型的实现)
// ElectronicGoods 电子产品结构体,实现了GoodsDisplay接口,内部组合了PaymentMethod
type ElectronicGoods struct {
payment PaymentMethod
}
func NewElectronicGoods(payment PaymentMethod) *ElectronicGoods {
return &ElectronicGoods{
payment: payment,
}
}
func (e *ElectronicGoods) ShowDetails() string {
return "这是一款电子产品,详情略,支持以下支付方式:"
}
func (e *ElectronicGoods) Buy(amount float64) bool {
return e.payment.Pay(amount)
}
// ClothingGoods 服装商品结构体,实现了GoodsDisplay接口,内部同样组合了PaymentMethod
type ClothingGoods struct {
payment PaymentMethod
}
func NewClothingGoods(payment PaymentMethod) *ClothingGoods {
return &ClothingGoods{
payment: payment,
}
}
func (c *ClothingGoods) ShowDetails() string {
return "这是一款服装商品,详情略,支持以下支付方式:"
}
func (c *ClothingGoods) Buy(amount float64) bool {
return c.payment.Pay(amount)
}
// BookGoods 图书商品结构体,实现了GoodsDisplay接口,内部组合了PaymentMethod
type BookGoods struct {
payment PaymentMethod
}
func NewBookGoods(payment PaymentMethod) *BookGoods {
return &BookGoods{
payment: payment,
}
}
func (b *BookGoods) ShowDetails() string {
return "这是一本图书商品,详情略,支持以下支付方式:"
}
func (b *BookGoods) Buy(amount float64) bool {
return b.payment.Pay(amount)
}
这里以电子产品、服装、图书三种商品类型为例,它们都实现了 GoodsDisplay
接口用于展示商品详情,并且内部都组合了 PaymentMethod
类型的对象,意味着它们可以使用不同的支付方式来完成购买操作(通过调用对应的 Pay
方法)。
最后进行测试使用:
func TestBridge(t *testing.T) {
// 创建微信支付实例
wechat := WeChatPayment{}
// 创建电子产品实例,并关联微信支付方式
electronic := NewElectronicGoods(wechat)
println(electronic.ShowDetails())
electronic.Buy(1000.0)
// 创建支付宝支付实例
alipay := AlipayPayment{}
// 创建服装商品实例,并关联支付宝支付方式
clothing := NewClothingGoods(alipay)
println(clothing.ShowDetails())
clothing.Buy(200.0)
// 创建银行卡支付实例
bankCard := BankCardPayment{}
// 创建图书商品实例,并关联银行卡支付方式
book := NewBookGoods(bankCard)
println(book.ShowDetails())
book.Buy(50.0)
}
本来呢桥接模式就像下面这样,中间像个桥,是GoodDisplay这个抽象体包含PaymentMethod抽象类的,这样才像一个桥一样。
但是go语言挺特殊,一般不是像上面那样设计,而是像下面这样,继承的子结构体包含PaymentMethod, GoodsDisplay则是定义成接口形式
优缺点
优点:
- 你可以创建与平台无关的类和程序。
- 客户端代码仅与高层抽象部分进行互动, 不会接触到平台的详细信息。
- 开闭原则。 你可以新增抽象部分和实现部分, 且它们之间不会相互影响。
- 单一职责原则。 抽象部分专注于处理高层逻辑, 实现部分处理平台细节。
缺点:
- 对高内聚的类使用该模式可能会让代码更加复杂。