外观模式
目录
定义
为子系统中的一组接口提供一个一致的界面,Facade
模式定义了一个高层接口、这个接口使得这一子系统更加容易使用。
其本质:封装交互,简化调用。
应用场景
代码生成器中有:模板生成器,逻辑生成器,数据生成器等。那么客户端就应该有相应的代码生成处理模块。
package main
import (
"fmt"
"sync"
)
//配置类
type Config struct {
IsGenView, IsGenDAO, IsGenService bool
}
func (c *Config) setIsGenView(b bool) {
c.IsGenView = b
}
func (c *Config) setIsGenDAO(b bool) {
c.IsGenDAO = b
}
func (c *Config) setIsGenService(b bool) {
c.IsGenService = b
}
func (c *Config) getIsGenView() bool {
return c.IsGenView
}
func (c *Config) getIsGenDAO() bool {
return c.IsGenDAO
}
func (c *Config) getIsGenService() bool {
return c.IsGenService
}
// ConfigManager 是一个配置管理器,使用单例模式实现
type ConfigManager struct {
config Config
}
var configManager *ConfigManager
var once sync.Once
func GetInstance() *ConfigManager {
once.Do(func() {
configManager = &ConfigManager{config: Config{
IsGenView: true,
IsGenDAO: true,
IsGenService: true,
}}
})
return configManager
}
//各个子系统模块
type View struct{}
type DAO struct{}
type Service struct{}
func (v *View) Generate() {
if GetInstance().config.IsGenView {
fmt.Println("View files has generate.")
}
}
func (d *DAO) Generate() {
if GetInstance().config.IsGenDAO {
fmt.Println("DAO files has generate.")
}
}
func (receiver *Service) Generate() {
if GetInstance().config.IsGenService {
fmt.Println("Service files has generate.")
}
}
func main() {
view := &View{}
dao := &DAO{}
svc := &Service{}
view.Generate()
dao.Generate()
svc.Generate()
}
以上代码,在客户端使用时候需要与子系统中多个模块交互,对于客户端而言,是一个麻烦,不能将简单的使用生成代码功能。而且如果某个子模块发生了变化,还可能引起客户端也要随着变化。
外观模式结构
Facade
: 定义子系统的多个模块对外的高层接口,通常需要调用内部多个模块,从而把客户的请求代理给适当的子系统对象
子模块接受Facade
对象的委派真正实现功能,各个模块之间可能有交互。 Facade
对象知道各个模块,但是各个子模块不应该知道 Facade
对象
示例代码
package main
import (
"fmt"
"sync"
)
//配置类
type Config struct {
IsGenView, IsGenDAO, IsGenService bool
}
// ConfigManager 是一个配置管理器,使用单例模式实现
type ConfigManager struct {
config Config
}
var configManager *ConfigManager
var once sync.Once
func GetInstance() *ConfigManager {
once.Do(func() {
configManager = &ConfigManager{config: Config{
IsGenView: true,
IsGenDAO: true,
IsGenService: true,
}}
})
return configManager
}
//各个子系统模块
type View struct{}
type DAO struct{}
type Service struct{}
func (v *View) Generate() {
if GetInstance().config.IsGenView {
fmt.Println("View files has generate.")
}
}
func (d *DAO) Generate() {
if GetInstance().config.IsGenDAO {
fmt.Println("DAO files has generate.")
}
}
func (receiver *Service) Generate() {
if GetInstance().config.IsGenService {
fmt.Println("Service files has generate.")
}
}
// 定义Facade
type Facade struct{}
// 将客户端需要实现的代码在Facade结构体中实现
func (f *Facade) Generate() {
view := &View{}
dao := &DAO{}
svc := &Service{}
view.Generate()
dao.Generate()
svc.Generate()
}
func main() {
//使用Facade对象
facade := &Facade{}
facade.Generate()
}
外观模式的目的
其不是给子系统添加新的功能,而是为了让外部减少与子系统内部多个模块的交互,松散耦合,从而让外部能够更简单的使用子系统。
因为外观模式是当作子系统对外的接口出现的,虽然也可以在Facade
中定义一些子系统中没有的功能,但是不建议这么做。外观应该是包装以有的功能,它主要负责组合已有功能来实现客户需要,而不是添加新的实现。
外观模式提供子系统中缺省的实现,即提供子系统中默认的实现。
Facade 方法只是实现一个功能的组合调用,其本身并不进行功能处理。
优缺点
-
优点
- 松散耦合
- 简单易用
- 更好地划分访问的层次
-
缺点
过多或者不太合理
Facade
也容易让人迷惑,到底调用Facade
好呢,还是直接调用模块好呢。
参考 - 研磨设计模式(外观模式)
阅读其他文章