门面模式也叫外观模式,英文为 Facade Design Pattern。门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。 门面模式的思想更常用在架构设计上,在编写代码层面大家很少提门面模式,但却一直在默默的使用。
UML类图位置:https://www.processon.com/diagraming/609b375407912943913a4c13
本文代码链接为:https://github.com/shidawuhen/asap/blob/master/controller/design/15facade.go
1定义
1.1门面模式
门面模式:为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
UML:
1.2分析
门面模式没有太多好分析的,思想比较简单。我方系统中包含多个子系统,完成一项任务需要多个子系统通力合作。
我们可以选择将子系统所有接口暴露给Client,让Client自行调用。但这会导致一些问题,一是后期沟通成本会很高,加入完成一个功能需要调用多个接口,Client联调时出问题率会飙升,系统提供者需要不断答疑。二是如果有多个Client,相同代码Client需要重复开发,而且后期代码有变更,各方都会很烦费力。三是影响响应时间和性能,多个接口往返,白白增加了很多通信时间和请求量。
另一种方式是,对于指定功能,系统端做好封装,只提供一个接口。好处有很多,沟通成本低、Client不需要重复开发、功能更改影响范围小、提高响应时间和性能。一般这些接口会有对应的OpenAPI,实现了功能对外开放的效果。
2.使用场景
对于使用场景,简单的举一个例子。
电商系统一般包含商品、库存、营销、商家、交易、支付、售后、履约、物流、仓储等子系统。拿商品详情页来说,商详页接口一般会涉及商品、库存、营销、商家等系统。电商系统的客户端有PC、Mobile、Android、IOS等,如果让这些客户端调用接口拼凑出商详页的数据,感觉客户端的同学能拿着大砍刀和服务端同学谈心。为了避免这种情况,一般商品组同学会提供商详页接口,该接口获取商详页的所有信息,返回给客户端。
当然,如果流量特别大,需要优化接口性能,可以根据具体情况将接口做拆分,客户端需要请求多个接口,但即使这样,相关的接口也是封装好的。如果真实场景中遇到这种拆分的情况,那恭喜你,说明公司在发展,流量在增加,能够推动大家更快的成长。
3.代码实现
门面模式应该是大家用的最自然的一种设计模式了。简单写一下电商系统的门面模式代码,以便和其它文章保持一致。
package main
import "fmt"
type ProductSystem struct {
}
func (p *ProductSystem) GetProductInfo() {
fmt.Println("获取到商品信息")
}
type StockSystem struct {
}
func (s *StockSystem) GetStockInfo() {
fmt.Println("获取到库存信息")
}
type PromotionSystem struct {
}
func (p *PromotionSystem) GetPromotionInfo() {
fmt.Println("获取营销信息")
}
func ProductDetail() {
product := &ProductSystem{}
stock := &StockSystem{}
promotion := &PromotionSystem{}
product.GetProductInfo()
stock.GetStockInfo()
promotion.GetPromotionInfo()
fmt.Println("整理完成商品详情页所有数据")
}
func main() {
ProductDetail()
}
输出:
➜ myproject go run main.go
获取到商品信息
获取到库存信息
获取营销信息
整理完成商品详情页所有数据
3.总结
门面模式是程序员最常用的一种设计模式了,在架构设计中往往自然而然的就会用到。很好的满足了接口隔离原则和迪米特法则。
最后
大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)
我的个人博客为:https://shidawuhen.github.io/