设计模式之桥接模式
概述
桥接模式 是一种结构型设计模式,系统中加入某个类存在两种独立变化的维度,可以通过该模式将这两个维度分离出来
桥接模式: 将抽象部分与其实现部分分离,使他们都可以独立变化,是一种对象结构型模式,又称为柄体模式或接口模式
桥接模式包含了4个角色:
- Abstraction(抽象类):用于定义抽象类的接口,既可以包含抽象业务方法,也可以包含具体业务方法
- RefinedAbstraction(扩充抽象类):扩充由Abstraction定义的接口,实现了Abstraction中声明的业务方法,并且可以调用在Implementor中定义的业务方法。
- Implementor(实现类接口):定义实现类的接口,它提供仅仅是一些基本操作,而Abstraction定义的接口会包含更多,更复杂的操作,在Abstraction中不仅可以拥有自己的方法,还可以调用Implementor中定义的方法
- ConcreteImplementor(具体实现类):具体实现Implementor接口,在不同的实现类中提供基本操作不同的实现
在使用桥接模式的时候需要识别出类具有两种独立变化的维度
数字和花色组合扑克牌
我们都知道扑克牌都有花色和数字,不同的花色和不同的数字可以用来表示不同的牌。所以我们这里使用扑克牌来举例,因为花色和数字正好是两个独立的维度
package bridge
import "fmt"
// AbstractionPoker 抽象类接口
type AbstractionPoker interface {
Combination() // 组合
}
// PokerImplementor 实现类接口
type PokerImplementor interface {
SetColor(string)
SetNum()
}
// NumberOne 具体实现类
type NumberOne struct {
}
func NewNumberOne() PokerImplementor {
return &NumberOne{}
}
func (n *NumberOne) SetNum() {
fmt.Println("poker number is one")
}
func (n *NumberOne) SetColor(color string) {
fmt.Printf("pocker color is %s\n", color)
}
type NumberTwo struct {
}
func NewNumberTwo() PokerImplementor{
return &NumberTwo{}
}
func (n *NumberTwo) SetNum() {
fmt.Println("poker number is two")
}
func (n *NumberTwo) SetColor(color string) {
fmt.Printf("pocker color is %s\n", color)
}
// ClubPoker 梅花扑克 拓展实现类
type ClubPoker struct {
pokerImplementor PokerImplementor
}
func NewClubPoker(impl PokerImplementor) *ClubPoker {
return &ClubPoker{
pokerImplementor: impl,
}
}
func (c *ClubPoker) Combination() {
c.pokerImplementor.SetColor("Club")
c.pokerImplementor.SetNum()
}
// HeartsPoker 拓展实现类
type HeartsPoker struct {
pokerImplementor PokerImplementor
}
func (h *HeartsPoker)Combination() {
h.pokerImplementor.SetColor("Heart")
h.pokerImplementor.SetNum()
}
func NewHeartPoker(impl PokerImplementor) *HeartsPoker {
return &HeartsPoker{
pokerImplementor: impl,
}
}
首先我们要明确,拓展实现类,实现的事Abstraction中的方法,而具体实现类实现的是Implementor中的方法,Implementor中定义了一些基础的方法,Abstraction中定义了复杂的方法。
// PokerImplementor 实现类接口
type PokerImplementor interface {
SetColor(string)
SetNum()
}
这里定义了PockerImplemetor实现类接口,定义了两个基础的方法,设置颜色和设置数字
// AbstractionPoker 抽象类
type AbstractionPoker interface {
Combination() // 组合
}
抽象类接口,这里定义了组合的方法作为复杂方法接口,接着我定义了两个扩充的结构体,用来实现Abstraction中的方法,并且在实现的过程中调用了Implementor的方法
// ClubPoker 梅花扑克
type ClubPoker struct {
pokerImplementor PokerImplementor
}
func NewClubPoker(impl PokerImplementor) *ClubPoker {
return &ClubPoker{
pokerImplementor: impl,
}
}
func (c *ClubPoker) Combination() {
c.pokerImplementor.SetColor("Club")
c.pokerImplementor.SetNum()
}
// HeartsPoker 红心扑克
type HeartsPoker struct {
pokerImplementor PokerImplementor
}
func (h *HeartsPoker)Combination() {
h.pokerImplementor.SetColor("Heart")
h.pokerImplementor.SetNum()
}
func NewHeartPoker(impl PokerImplementor) *HeartsPoker {
return &HeartsPoker{
pokerImplementor: impl,
}
}
同时也定义两个具体实现类去实现Implementor的方法
// NumberOne 拓展实现类
type NumberOne struct {
}
func NewNumberOne() PokerImplementor {
return &NumberOne{}
}
func (n *NumberOne) SetNum() {
fmt.Println("poker number is one")
}
func (n *NumberOne) SetColor(color string) {
fmt.Printf("pocker color is %s\n", color)
}
type NumberTwo struct {
}
func NewNumberTwo() PokerImplementor{
return &NumberTwo{}
}
func (n *NumberTwo) SetNum() {
fmt.Println("poker number is two")
}
func (n *NumberTwo) SetColor(color string) {
fmt.Printf("pocker color is %s\n", color)
}
这样的设置就满足了桥接模式的所有角色设定
测试
package bridge
import (
"fmt"
"testing"
)
func TestClubPoker_Combination(t *testing.T) {
clubPokerOne := NewClubPoker(NewNumberOne())
clubPokerOne.Combination()
fmt.Println()
heartPokerTwo := NewHeartPoker(NewNumberTwo())
heartPokerTwo.Combination()
}
//
// === RUN TestClubPoker_Combination
// pocker color is Club
// poker number is one
//
// pocker color is Heart
// poker number is two
// --- PASS: TestClubPoker_Combination (0.00s)
// PASS
总结
优点
- 提高了系统的可拓展型,两个维度任意增加一种维度,都不需要修改原有的系统,符合开闭原则
缺点
- 复杂,比较难,比较难去抽象,同时叶需要精准识别出两个独立变化的维度