

手撸golang 结构型设计模式 门面模式
source link: https://studygolang.com/articles/33096
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

手撸golang 结构型设计模式 门面模式
缘起
最近复习设计模式
拜读谭勇德的<<设计模式就该这样学>>
本系列笔记拟采用golang练习之
门面模式
门面模式(Facade Pattern)又叫作外观模式,提供了一个统一的接口,用来访问子系统中的一群接口。其主要特征是定义了一个高层接口,让子系统更容易使用,属于结构型设计模式。
_
场景
- 某在线商城, 推出了积分兑换礼品的功能
- 兑换礼品有几个步骤, 涉及到若干子系统:
- 积分系统, 检查用户积分是否足够
- 库存系统, 检查礼品是否有库存
- 物流系统, 安排礼品发货并生成发货订单
- 为简化业务层接口, 以门面模式设计统一的积分兑换API接口 - IGiftExchangeService
设计
- GiftInfo: 礼品信息实体. 礼品也是一种库存物品.
- GiftExchangeRequest: 积分兑换礼品申请
- IGiftExchangeService: 积分兑换礼品服务, 该服务是一个Facade, 内部调用了多个子系统的服务
- IPointsService: 用户积分管理服务的接口
- IInventoryService: 库存管理服务的接口
- IShippingService: 物流下单服务的接口
- tMockGiftExchangeService: 积分兑换礼品服务的实现类
- tMockPointsService: 用户积分管理服务的实现类
- tMockInventoryService: 库存管理服务的实现类
- tMockShippingService: 物流下单服务的实现类
单元测试
facade_pattern_test.go
package structural_patterns import ( "learning/gooop/structural_patterns/facade" "testing" "time" ) func Test_FacadePattern(t *testing.T) { iUserID := 1 iGiftID := 2 // 预先存入1000积分 e := facade.MockPointsService.SaveUserPoints(iUserID, 1000) if e != nil { t.Error(e) return } // 预先存入1个库存 e = facade.MockInventoryService.SaveStock(iGiftID, 1) if e != nil { t.Error(e) return } request := &facade.GiftExchangeRequest{ ID: 1, UserID: iUserID, GiftID: iGiftID, CreateTime: time.Now().Unix(), } e, sOrderNo := facade.MockGiftExchangeService.Exchange(request) if e != nil { t.Log(e) } t.Logf("shipping order no = %v", sOrderNo) }
测试输出
$ go test -v facade_pattern_test.go === RUN Test_FacadePattern facade_pattern_test.go:36: shipping order no = shipping-order-666 --- PASS: Test_FacadePattern (0.00s) PASS ok command-line-arguments 0.002s
GiftInfo.go
礼品信息实体
package facade type GiftInfo struct { ID int Name string Points int } func NewGiftInfo(id int, name string, points int) *GiftInfo { return &GiftInfo{ id, name, points, } }
GiftExchangeRequest.go
积分兑换礼品请求
package facade type GiftExchangeRequest struct { ID int UserID int GiftID int CreateTime int64 }
IGiftExchangeService.go
积分兑换礼品的接口, 该接口是为方便客户端调用的Facade接口
package facade // 礼品兑换服务 type IGiftExchangeService interface { // 兑换礼品, 并返回物流单号 Exchange(request *GiftExchangeRequest) (error, string) }
IPointsService.go
模拟用户积分管理服务的接口
package facade // 用户积分服务 type IPointsService interface { GetUserPoints(uid int) (error, int) SaveUserPoints(uid int, points int) error }
IInventoryService.go
模拟库存管理服务的接口
package facade // 库存服务 type IInventoryService interface { GetGift(goodsID int) *GiftInfo GetStock(goodsID int) (error, int) SaveStock(goodsID int, num int) error }
IShippingService.go
模拟物流下单服务的接口
package facade // 物流下单服务 type IShippingService interface { CreateShippingOrder(uid int, goodsID int) (error, string) }
tMockGiftExchangeService.go
实现积分兑换礼品服务. 内部封装了积分服务, 库存服务和物流下单服务的调用.
package facade import "errors" type tMockGiftExchangeService struct { } func newMockGiftExchangeService() IGiftExchangeService { return &tMockGiftExchangeService{} } var MockGiftExchangeService = newMockGiftExchangeService() // 模拟环境下未考虑事务提交和回滚 func (me *tMockGiftExchangeService) Exchange(request *GiftExchangeRequest) (error, string) { gift := MockInventoryService.GetGift(request.GiftID) if gift == nil { return errors.New("gift not found"), "" } e, points := MockPointsService.GetUserPoints(request.UserID) if e != nil { return e, "" } if points < gift.Points { return errors.New("insufficient user points"), "" } e, stock := MockInventoryService.GetStock(gift.ID) if e != nil { return e, "" } if stock <= 0 { return errors.New("insufficient gift stock"), "" } e = MockInventoryService.SaveStock(gift.ID, stock-1) if e != nil { return e, "" } e = MockPointsService.SaveUserPoints(request.UserID, points - gift.Points) if e != nil { return e, "" } e,orderNo := MockShippingService.CreateShippingOrder(request.UserID, gift.ID) if e != nil { return e, "" } return nil, orderNo }
tMockPointsService.go
���拟实现用户积分管理服务
package facade import "errors" var MockPointsService = newMockPointsService() type tMockPointsService struct { mUserPoints map[int]int } func newMockPointsService() IPointsService { return &tMockPointsService{ make(map[int]int, 16), } } func (me *tMockPointsService) GetUserPoints(uid int) (error, int) { n,ok := me.mUserPoints[uid] if ok { return nil, n } else { return errors.New("user not found"), 0 } } func (me *tMockPointsService) SaveUserPoints(uid int, points int) error { me.mUserPoints[uid] = points return nil }
tMockInventoryService.go
模拟实现库存管理服务
package facade var MockInventoryService = newMockInventoryService() type tMockInventoryService struct { mGoodsStock map[int]int } func newMockInventoryService() IInventoryService { return &tMockInventoryService{ make(map[int]int, 16), } } func (me *tMockInventoryService) GetGift(id int) *GiftInfo { return NewGiftInfo(id, "mock gift", 100) } func (me *tMockInventoryService) GetStock(goodsID int) (error, int) { n,ok := me.mGoodsStock[goodsID] if ok { return nil, n } else { return nil, 0 } } func (me *tMockInventoryService) SaveStock(goodsID int, num int) error { me.mGoodsStock[goodsID] = num return nil }
tMockShippingService.go
模拟实现物流下单服务
package facade var MockShippingService = newMockShippingService() type tMockShippingService struct { } func newMockShippingService() IShippingService { return &tMockShippingService{} } func (me *tMockShippingService) CreateShippingOrder(uid int, goodsID int) (error, string) { return nil, "shipping-order-666" }
门面模式小结
门面模式的优点
(1)简化了调用过程,不用深入了解子系统,以防给子系统带来风险。
(2)减少系统依赖,松散耦合。
(3)更好地划分访问层次,提高了安全性。
(4)遵循迪米特法则
门面模式的缺点
(1)当增加子系统和扩展子系统行为时,可能容易带来未知风险。
(2)不符合开闭原则。
(3)某些情况下,可能违背单一职责原则。
(end)
有疑问加站长微信联系(非本文作者)

Recommend
-
11
手撸golang 结构型设计模式 装饰器模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 装饰器模式 装饰器模式(Decora...
-
10
手撸golang 结构型设计模式 组合模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 组合模式 组合模式(Composite...
-
16
手撸golang 行为型设计模式 委派模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 委派模式 委派模式(Delegate...
-
5
手撸golang 行为型设计模式 策略模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 策略模式 策略模式(Strategy Patter...
-
18
手撸golang 行为型设计模式 责任链模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 责任链模式 责任链模式(Chain of...
-
9
手撸golang 行为型设计模式 迭代器模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 迭代器模式 迭代器模式(Iterator...
-
11
手撸golang 行为型设计模式 备忘录模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 备忘录模式 备忘录模式(Memento P...
-
11
手撸golang 行为型设计模式 中介者模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 中介者模式 中介者模式(Mediator...
-
11
手撸golang 行为型设计模式 观察者模式 缘起 最近复习设计模式 拜读谭勇德的<<设计模式就该这样学>> 本系列笔记拟采用golang练习之 观察者模式 观察者模式(Observer...
-
5
前面介绍了设计模式中的建造型模式,这篇介绍结构型模式的一部分。主要是适配器模式、装饰器模式、代理模式的设计说明 描述将类和对象结合在一起,形成一个更强大的结构。 类结构型模式:关心类的组合,由多个类...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK