外观模式
概念
外观模式又叫门面模式,是一种常用的封装模式
给一系列具有关联性的子系统的集合提供对外访问的一组接口,调用者不用明确内部具体的业务逻辑,只需要调用这组接口达到目的即可。也就是要求子系统外部与内部不能直接进行通讯,必须通过一个统一的对象进行,而这个统一的对象就是门面。门面模式通过只提供高层次的接口,从而降低了外部与子系统调用的复杂性。
使用场景
A. 为一组子系统或一系列复杂的模块提供一个统一的外部访问的接口。
B. 调用方与子系统依赖性很强,通过门面将 client 与子系统强依赖转化门面对象间的依赖。
优点
减少了系统的相互依赖性;在我看来通过门面的代理,直接切断了调用方与各个子系统内部的调用关系,降低了双方的耦合关系,从而降低了系统混乱、依赖。直接将两者的依赖关系转移到门面对象之间的依赖,减少了直接与子系统间的相互依赖关系,符合设计原则。
功能拓展性更灵活,只要不影响门面对象,子系统内部可以多样性。
- 通过门面对外只提供必要的服务与直接对外暴露子系统服务而言,系统的安全性更高。
缺点
不满足开闭原则,外观修改风险性很大。
代码实现
文件结构
├── facade.go
├── facade_test.go
├── policeInspection.go
├── samplefacade.go
└── sampleletters.go
facade.go
package facade
type Facade interface {
sendLetter(context, address string)
}
sampleletters.go
type SampleLetters struct {
letter string
}
func (sl *SampleLetters) WriteLetters(content string) {
sl.letter = fmt.Sprintf("信件内容为:%s", content)
}
func (sl *SampleLetters) AddAddress(address string) {
sl.letter += "\n" + fmt.Sprintf("邮寄至:%s", address)
}
func (sl *SampleLetters) PutIntoEnvelope() {
fmt.Println("信件放入信封中...")
}
func (sl *SampleLetters) SendLetters() {
fmt.Println("信件已发送....")
}
simlefacade.go
type SampleFacade struct {
SampleLetters
PoliceInspection
}
func NewSampleFacade() *SampleFacade {
return &SampleFacade{}
}
func (sf *SampleFacade) sendLetter(content, address string) {
sf.WriteLetters(content)
sf.AddAddress(address)
ok := sf.CheckLetterSecurity(sf.letter)
if !ok {
fmt.Println("信件内容不安全")
return
}
fmt.Println("信件内容很安全")
sf.PutIntoEnvelope()
sf.SendLetters()
}
policeinspection.go
type PoliceInspection struct{}
func (PoliceInspection) CheckLetterSecurity(content string) bool {
fmt.Printf("被检查内容:%s\n", content)
fmt.Println("内容检查通过...")
return true
}
代码测试
func TestNewFacade(t *testing.T) {
var facade Facade = NewSampleFacade()
facade.sendLetter(
"Hello dear, facade design pattern...",
"example@example.cn",
)
}
测试结果
=== RUN TestNewFacade
被检查内容:Hello dear, facade design pattern...
内容检查通过...
信件内容很安全
信件放入信封中...
信件已发送....
--- PASS: TestNewFacade (0.00s)
PASS
ok ginstudy/facade 0.004s