桥接模式
1、桥接模式原理
将抽象和实现解耦,使他们可以独立变化。根据这个定义我们很难理解是什么意思,其实可以通过这样解释:
一个类存在两个及两个以上变化的维度,我们可以通过组合方式,使两个维度都可以独立扩展。
Abstraction:抽象化角色,具体实现需要保存一个实现化角色引用,目的是使Operation调用实现化角色的OperationImp
RefinedAbstraction:抽象化角色具体实现,调用implementor的OperationImp
Implementor:实现化角色抽象
ConcreteImplementor:实现化角色具体实现,提供具体操作方法XXOperationImp,为RefinedAbstraction提供真实的操作方法
有UML图看Abstraction和Implementor间架设一座桥梁,RefinedAbstraction可以通过这座桥调用真实的操作方法(ConcreteImplementor的XXOperationImp方法),桥通过聚合方式实现
2、具体场景
现在有个需求,要做一个服务监控告警程序,告警方式可以是微信消息、短信消息、自动语言电话告警。同时告警级别有分,普通、重要、紧急。不同的告警级别对应不同的通知方式。
可能第一反应考虑到实现方案为:
const (
NORMAL = 1
IMPORTANT = 2
URGENCY = 3
)
func client() {
Notice(IMPORTANT, "server-10 memory usage exceeds 75%")
}
func Notice(level int, message string) {
switch level {
case NORMAL:
//微信告警
case IMPORTANT:
//短信告警
case URGENCY:
//自动语音电话告警
}
}
这种方案当然没有问题,但是不利于扩展,如果现在有需求告警级别为普通,但想用短信告警。这种两个维度两两组合的需求就很难扩展。这个时候就可以考虑使用桥接模式
将消息作为抽象化角色Message,抽象角色具体实现为普通消息、重要消息、紧急消息
实现角色为各级别发送器Notification,实现角色具体实现为微信发送、短信发送、语音发送
抽象化具体角色XXMessage聚合消息发送器Notification
bridge.go
package bridge
import "fmt"
type Message interface {
SendMessage(message string)
}
type Notification interface {
Send(message string)
}
type WeiXinNotification struct{}
func NewWeiXinNotification() Notification {
return &WeiXinNotification{}
}
func (*WeiXinNotification) Send(message string) {
fmt.Printf("%s send [weixin] message \n", message)
}
type SMSNotification struct{}
func NewSMSNotification() Notification {
return &SMSNotification{}
}
func (*SMSNotification) Send(message string) {
fmt.Printf("%s send [sms] message \n", message)
}
type PhoneNotification struct{}
func NewPhoneNotification() Notification {
return &PhoneNotification{}
}
func (*PhoneNotification) Send(message string) {
fmt.Printf("%s send [phone] message \n", message)
}
type CommonMessage struct {
notification Notification
}
func NewCommonMessage(notification Notification) *CommonMessage {
return &CommonMessage{
notification: notification,
}
}
func (m *CommonMessage) SendMessage(message string) {
m.notification.Send("[Common] notice " + message)
}
type ImportantMessage struct {
notification Notification
}
func NewImportantMessage(notification Notification) *ImportantMessage {
return &ImportantMessage{
notification: notification,
}
}
func (m *ImportantMessage) SendMessage(message string) {
m.notification.Send("[Important] notice " + message)
}
type UrgencyMessage struct {
notification Notification
}
func NewUrgencyMessage(notification Notification) *UrgencyMessage {
return &UrgencyMessage{
notification: notification,
}
}
func (m *UrgencyMessage) SendMessage(message string) {
m.notification.Send("[Urgency] notice " + message)
}
bridge_test.go
package bridge
import "testing"
func TestExampleCommonWeiXin(t *testing.T) {
m := NewCommonMessage(NewWeiXinNotification())
m.SendMessage("memory usage exceeds 50%")
}
func TestExampleCommonSMS(t *testing.T) {
m := NewCommonMessage(NewSMSNotification())
m.SendMessage("memory usage exceeds 50%")
}
func TestExampleImportantSMS(t *testing.T) {
m := NewImportantMessage(NewSMSNotification())
m.SendMessage("memory usage exceeds 60%")
}
func TestExampleImportantWeixin(t *testing.T) {
m := NewImportantMessage(NewWeiXinNotification())
m.SendMessage("memory usage exceeds 60%")
}
func TestExampleUrgencySMS(t *testing.T) {
m := NewUrgencyMessage(NewSMSNotification())
m.SendMessage("memory usage exceeds 70%")
}
func TestExampleUrgencyPhone(t *testing.T) {
m := NewUrgencyMessage(NewPhoneNotification())
m.SendMessage("memory usage exceeds 70%")
}