最近关于访问者模式的一些设计

最近关于访问者模式的一些设计

场景

财务系统需要支持多个不同的业务场景的接入。

一方面,可以预见不同的业务场景,从数据来源、字段类型、计算逻辑、审批流转、单据聚合等等都可能会不一样。

另一方面,财务系统又要提供一个统一的入口,对不同业务场景进行结算。对于不同的业务场景,尽管整体上与常规结算流程相似,但具体实现其实各有各的样子。

为了能有统一入口,不能简单的对每个场景都拷贝一份新的流程。但如果要在一个流程里处理各种业务的逻辑,随着业务场景的增加,不加设计的话不可避免会出现大量的if代码,最终导致难以维护。

访问者模式

场景:LD跟HR需要对RD与PM进行绩效考核。RD与PM的工作不一样,考核标准自然不一样,并且HR跟LD对考核的关注点也不一样。

  • 简单的想法,是对RD/PM抽象为一个员工接口,让每个员工实现自评,LD/HR就不需要知道这个员工具体是谁,调用自己关心的计算绩效方法就好
  • 因为计算绩效的代码在RD/PM里实现,会对RD/PM都有很大的入侵。如果以后还有更多需要上报的对象,那RD/PM对绩效计算逻辑的维护将会是一个很大的负担
  • 并且RD负责的是写代码,PM负责的是写PRD。计算绩效权责上并不属于RD/PM,而是属于LD/HR的。因此将计算绩效的实现放在RD/PM里是有一定的不合理的

  • 按访问者模式设计的话,会讲LD/HR都抽象为一个考核员,这个考核员就是访问者模式里的访问者-Visitor
  • RD/PM依然需要被抽象为员工接口,但只需要给考核员提供一个绩效会议的接口进行访问,而无需关注考核员具体是谁
  • 在绩效会议方法中,考核员会给RD/PM提供填写绩效数据接口。虽然既有RD也有PM的绩效数据填写接口,但RD/PM只需要填自己那部分就好。填好后绩效由LD/HR自己去计算
  • 这样RD/PM只需要填写绩效数据就好,由于填写的内容是比较稳定的,这样RD/PM的逻辑就会更加稳定和轻量
  • 如果以后有更多需要上报的对象,只需要新增考核员的具体实现即可,不会影响到RD/PM本身

1
2
3
4
5
6
7
8
9
10
11
12
13
type Employee interface { Meet(visitor) }
type Visitor interface { SetRd(CodeCnt); SetPm(PrdCnt) }

type RD struct { CodeCnt int }
func (rd *RD) Meet(visitor) { visitor.SetRd(rd.CodeCnt) }

type LD struct {}
func (ld *LD) SetRd(cnt) { "RD写了多少代码:"+cnt }
func (ld *LD) SetPm(cnt) { "不关心" }

var employee Employee = new(RD)
var visitor Visitor = new(LD)
employee.Meet(visitor)

改造访问者模式

  • 访问者模式里,之所以能在不感知具体业务数据的前提下,将数据传递给Visitor,是因为传递业务数据是在Data的具体实现里。
  • 利用这个想法扩展一下思路,不仅把Data跟Visitor的数据传递放到Data的实现里,Visitor的实例化也放到Data的实现里,使得实例化出来的Visitor符合Data。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Employee interface { Meet(visitor) }
type Visitor interface { SetRd(CodeCnt); SetPm(PrdCnt) }

type RD struct { CodeCnt int }
func (rd *RD) Meet() {
var ld LD = new(LD)
ld.SetRd(rd.CodeCnt)
}

type LD struct {}
func (ld *LD) SetRd(cnt) { "RD写了多少代码:"+cnt }
func (ld *LD) SetPm(cnt) { "不关心" }

var employee Employee = new(RD)
employee.Meet()
  • 首先以Visitor维度,将Data接口(下文改名叫Manager)的方法权责最小化
  • 例如一个负责查询消耗的Visitor,Visitor查到消耗之后只需要找地方存放消耗数据就好,因此Manager只需要一个set消耗的方法即可

1
2
3
4
5
6
type AdCostQueryManager interface { SetAdCost(AdCost) }

func (v *AdCostQueryVisitor) Exec(manager AdCostQueryManager) {
var cost AdCost = ListAdCost()
manager.SetAdCost(cost)
}
  • 以一个功能/RPC接口为维度,把这个功能涉及到数据封装在ManagerImpl里。
  • 一方面,为了使得Visitor能够访问数据,ManagerImpl会实现Visitor所需要的Manager接口。
  • 另一方面,ManagerImpl决定实例化哪些Visitor以及Visitor的处理顺序,负责确保所选择的Visitor能正确处理该功能的数据。

1
2
3
4
5
6
7
type AdBillGenManagerImpl struct { Cost AdCost; Bill Bill }

func (a *AdBillGenManagerImpl) GenBill(req) {
NewAdCostQueryVisitor(req).Exec(a)
NewAdBillGenVisitor().Exec(a)
insert_into(a.Bill)
}

责任链模式

  • Visitor除了提供的代码复用能力以外,Visitor本身可以拓展其他的设计模式来支持能加灵活的功能。这里使用责任链将Visitor改造一下
  • AbstractVisitor将Visitor改造为一个链表中的节点
  • AbstractManager给ManagerImpl增加链表功能
  • ManagerImpl就能调用头节点的Visitor,调用整个责任链的逻辑了
  • 责任链模式支持了Visitor的运行时多态,将能实现类似于面板配置结算流程这样的功能

1
2
3
4
5
func (this *AdBillGenManagerImpl) GenBill(req GenBillReq) {
this.LinK.Append(NewAdCostQueryVisitor(req))
this.LinK.Append(NewAdBillGenVisitor())
this.LinK.Exec(this)
}

模式比较

这里可能还有个疑问,为什么设计一个Visitor的概念,让ManagerImpl调用Visitor

  • ManagerImpl通过去调用一些公共方法,这些公共方法也一样能提供复用能力。
  • Visitor的角色确实跟公共方法非常相似,其实整个设计模式跟普通的公共方法调用也非常相似,只不过其中加了访问者模式的一些技巧。
  • 但Visitor与公共方法最本质的区别是,Visitor除了提供搭配责任链等其他设计模式,这种公共方法无法做到的花哨效果以外,如果公共方法不想跟具体场景耦合,是没有办法把覆盖全部的逻辑的。
  • 这使得总会有一些逻辑是裸露在ManagerImpl里。而这些裸露的逻辑就只能依靠复制粘贴来实现复用。
1
2
3
4
5
6
7
8
9
10
11
12
13
type AdManagerImpl struct { CostA Cost; CostB Cost }
func (a *AdManagerImpl) GenBill(req) {
var cost Cost = ListCost() //公共方法
if a.CostA==nil : a.CostA = cost
else a.CostB = cost
}

type CpaManagerImpl struct { CostA Cost; CostB Cost }
func (c *CpaManagerImpl) GenBill(req) {
var cost Cost = ListCost() //公共方法
if c.CostA==nil : c.CostA = cost
else c.CostB = cost
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type AdManagerImpl struct { CostA Cost; CostB Cost }
func (a *AdManagerImpl) GenBill(req) {
NewCostQueryVisitor(req).Exec(a)
}

type CpaManagerImpl struct { CostA Cost; CostB Cost }
func (c *CpaManagerImpl) GenBill(req) {
NewCostQueryVisitor(req).Exec(c)
}

func (v *CostQueryVisitor) Exec(manager AdGenBillManagerImpl) {
var cost Cost = ListCost() //公共方法
if manager.ListCostA()==nil : manager.SetCostA(cost)
else manager.SetCostB(cost)
}

对照一下目标

  • 这套接口流程既要与常规结算流程尽可能的像,又要能够较低成本的拓展新业务场景
  • 各个业务场景的代码既要尽可能的解耦,又要在解耦的同时有一定的代码复用能力
改版访问者模式 继承重写 公共方法与if
ManagerImpl通过向上转型为接口,对上层代码屏蔽了具体数据。由于Visitor是由ManagerImpl进行实例化,因此也实现了对业务逻辑的屏蔽 通过子类继承基类,并将子类向上转型,给上层代码提供了一个统一的调用入口。向上转型屏蔽了子类场景的数据类型与业务逻辑 不屏蔽,全部场景的具体数据与逻辑都由上层代码负责维护
一个功能/RPC接口对应一个ManagerImpl,各个ManagerImpl相互独立。能使得对于大多数只会在某个场景里使用的逻辑,只需要实现该场景的ManagerImpl即可,对其他ManagerImpl没有影响 需要在基类增加抽象方法供上层代码调用。这使得全部子类都得实现该方法,哪怕该方法的功能只会在某个场景里使用,其他场景也得实现空接口。上层代码还要担心是否会调用到空方法而抛异常 公共方法直接是相互独立,比较没什么影响。但如果是使用if来支持特殊场景将很容易影响到现有逻辑
一个功能/RPC接口对应一个ManagerImpl,各个ManagerImpl相互独立。能使得对于大多数只会在某个场景里使用的逻辑,只需要实现该场景的ManagerImpl即可,对其他ManagerImpl没有影响 需要在基类增加抽象方法供上层代码调用。这使得全部子类都得实现该方法,哪怕该方法的功能只会在某个场景里使用,其他场景也得实现空接口。上层代码还要担心是否会调用到空方法而抛异常 公共方法直接是相互独立,比较没什么影响。但如果是使用if来支持特殊场景将很容易影响到现有逻辑
在ManagerImpl中选择使用哪些Visitor是高度自由的,Visitor之间的顺序也是高度自由的。并且对于Visitor的概念,可以对应到结算流程里对账单/结算单/对公单步骤,也可以对应到查询消耗/生成账单/保存账单这些更细粒度的步骤。因为能有很大空间去使用各种Visitor,去串出一条符合实际场景的结算流程 每个方法的逻辑范围与方法之间的调用关系被基类设计过。在不影响基类的前提下,子类的定制化空间并不大 没有任何模式的约束,权责与分层最为灵活也最容易混乱
ManagerImpl跟Visitor是高度解耦的,也就是数据与逻辑是高度解耦的。通过Visitor自己定义Manager接口,实现与具体的ManagerImpl解耦。哪怕ManagerImpl有冗余的getset方法,对Visitor是即无感知也无影响 数据与逻辑是高度耦合的。数据就是类的成员变量,逻辑就是类的成员方法 如果该方法要实现具体场景的逻辑,那数据与逻辑就是高度耦合的。数据就是方法的局部变量,逻辑就是方法本身
Visitor是高度可复用的。例如查询账单的Visitor,他自己并不感知也不关心他查询到的的账单最终会被用作干嘛,或者是被用来生成结算单,或者是用于页面展示。换句话说查询账单的Visitor可以被用在生成结算单Manager里,也可以被用在账单列表查询Manager里 子类能复用自己以及父类的逻辑,但是对应对于自己的子类/兄弟类/舅舅阿姨类的逻辑则难以复用 通过公共方法实现部分复用性,但与实现具体场景相关的逻辑难以优雅复用
为了实现代码复用,将整个长长的处理流程切割成了很多个小Visitor。开发中需要了解他所使用Visitor直接的处理是否能衔接上 子类通过实现父类的抽象方法,并且父类提供了默认的方法调用流程的实现,能一定程度上保障各部分的代码逻辑能衔接上 如果公共方法切割的小,一样也会增加处理衔接的成本和风险。但是方法的出入参能对代码的衔接做出一定的提醒校验作用

代码层级

整体上依然是经典的handler层,Service层与持久层的。但是将Service层再细化分为三层

  • 业务层:感知具体场景的数据与逻辑。不同业务之间的数据与处理流程使用代码包互相隔离,代码通过Visitor进行复用。每个代码包只实现一个业务,也只关注自己的业务
  • 混合层:只感知具体场景的数据,不感知逻辑。负责将请求分派给各个场景进行处理,汇总不同场景的处理结果进行返回
  • 入口层:不感知具体场景的数据与逻辑。负责处理与场景无关的逻辑,并且对接handler层

DEMO代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
package main

import (
"fmt"
"time"
)

func main() {

{
fmt.Println()
fmt.Printf("查询消耗生成对账单\n")
manager := NewMixManager()
resp, err := manager.GenBill(GenBillReq{BizType: []string{"AD", "CPA"}, Len: 1})
if err != nil {
panic(err)
}
fmt.Printf("查询消耗生成对账单: %+v\n", resp)
time.Sleep(time.Second)
}
{
fmt.Println()
fmt.Printf("查询对账单生成结算单\n")
manager := NewMixManager()
resp, err := manager.GenSettle(GenSettleReq{BizType: []string{"AD", "CPA"}, Len: 2})
if err != nil {
panic(err)
}
fmt.Printf("查询对账单生成结算单: %+v\n", resp)
time.Sleep(time.Second)
}

}

//handler

type GenBillReq struct {
BizType []string
Len int
}
type GenBillResp struct {
Data interface{}
}
type GenSettleReq struct {
BizType []string
Len int
}
type GenSettleResp struct {
Data interface{}
}

func NewMixManager() *MixManager {
object := new(MixManager)
return object
}

type MixManager struct {
}

func (this *MixManager) GenBill(req GenBillReq) (*GenBillResp, error) {
type GenBillManager interface {
GenBill(req GenBillReq) (*GenBillResp, error)
ListBill() []*Bill
}
var manager []GenBillManager
for i := range req.BizType {
switch req.BizType[i] {
case "AD":
manager = append(manager, NewAdGenBillManagerImpl())
case "CPA":
manager = append(manager, NewCpaGenBillManagerImpl())
default:
panic("未实现业务类型")
}
}
for i := range manager {
manager[i].GenBill(req)
}
var bill []*Bill
for i := range manager {
bill = append(bill, manager[i].ListBill()...)
}
resp := new(GenBillResp)
resp.Data = bill
return resp, nil
}
func (this *MixManager) GenSettle(req GenSettleReq) (*GenSettleResp, error) {
type GenSettleManager interface {
GenSettle(req GenSettleReq) (*GenSettleResp, error)
ListSettle() []*Settle
}
var manager []GenSettleManager
for i := range req.BizType {
switch req.BizType[i] {
case "AD":
manager = append(manager, NewAdGenSettleManagerImpl())
case "CPA":
manager = append(manager, NewCpaGenSettleManagerImpl())
default:
panic("未实现业务类型")
}
}
for i := range manager {
manager[i].GenSettle(req)
}
var settle []*Settle
for i := range manager {
settle = append(settle, manager[i].ListSettle()...)
}
resp := new(GenSettleResp)
resp.Data = settle
return resp, nil
}

//model

type CpaCost struct {
}
type AdCost struct {
}
type Bill struct {
}
type Settle struct {
}

//common

func GenBill(cost ...interface{}) []*Bill {
//虽然AD跟CPA的BillVisitor是各有一个
//但既然AD跟CPA生成账单的逻辑一样
//那按道理能把CPA跟AD的消耗抽象为一个接口
//经同一个代码块进行处理
bill := make([]*Bill, len(cost))
for i := range bill {
bill[i] = new(Bill)
}
return bill
}

type Visitor[Manager any] interface {
SetNext(object Visitor[Manager])
Exec(manager Manager) error
}

func NewAbstractVisitor[Manager any]() *AbstractVisitor[Manager] {
object := new(AbstractVisitor[Manager])
return object
}

type AbstractVisitor[Manager any] struct {
Next Visitor[Manager]
}

func (this *AbstractVisitor[Manager]) SetNext(object Visitor[Manager]) {
this.Next = object
}
func (this *AbstractVisitor[Manager]) ExecNext(manager Manager) error {
if this.Next == nil {
return nil
}
return this.Next.Exec(manager)
}

func NewAbstractManager[Manager any]() *AbstractManager[Manager] {
object := new(AbstractManager[Manager])
return object
}

type AbstractManager[Manager any] struct {
Head Visitor[Manager]
Tail Visitor[Manager]
}

func (this *AbstractManager[Manager]) Append(object Visitor[Manager]) {
if object == nil {
return
}
if this.Tail == nil {
this.Head = object
this.Tail = object
}
this.Tail.SetNext(object)
this.Tail = object
}
func (this *AbstractManager[Manager]) Exec(manager Manager) error {
if this.Head == nil {
return nil
}
return this.Head.Exec(manager)
}

func NewAsyncVisitor[Manager AsyncManager]() *AsyncVisitor[Manager] {
object := new(AsyncVisitor[Manager])
object.AbstractVisitor = NewAbstractVisitor[Manager]()
return object
}

type AsyncManager interface {
ListBill() []*Bill
SetSettle(object ...*Settle)
}

type AsyncVisitor[Manager AsyncManager] struct {
*AbstractVisitor[Manager]
}

func (this *AsyncVisitor[Manager]) Exec(manager Manager) error {
fmt.Printf("异步执行其他Visitor: %T\n", this.Next)
go func() {
this.ExecNext(manager)
}()
return nil
}

func NewGenSettleVisitor[Manager GenSettleManager]() *GenSettleVisitor[Manager] {
object := new(GenSettleVisitor[Manager])
object.AbstractVisitor = NewAbstractVisitor[Manager]()
return object
}

type GenSettleManager interface {
ListBill() []*Bill
SetSettle(object ...*Settle)
}

type GenSettleVisitor[Manager GenSettleManager] struct {
*AbstractVisitor[Manager]
}

func (this *GenSettleVisitor[Manager]) Exec(manager Manager) error {
bill := manager.ListBill()
fmt.Printf("使用Bill生成结算单: %+v\n", bill)
settle := make([]*Settle, len(bill))
for i := range settle {
settle[i] = new(Settle)
}
manager.SetSettle(settle...)
return this.ExecNext(manager)
}

//cpa

func NewCpaGenBillManagerImpl() *CpaGenBillManagerImpl {
object := new(CpaGenBillManagerImpl)
object.AbstractManager = NewAbstractManager[*CpaGenBillManagerImpl]()
return object
}

type CpaGenBillManagerImpl struct {
*AbstractManager[*CpaGenBillManagerImpl]
Cost []*CpaCost
Bill []*Bill
}

func (this *CpaGenBillManagerImpl) ListCost() []*CpaCost {
return this.Cost
}
func (this *CpaGenBillManagerImpl) SetCost(object ...*CpaCost) {
this.Cost = object
}
func (this *CpaGenBillManagerImpl) ListBill() []*Bill {
return this.Bill
}
func (this *CpaGenBillManagerImpl) SetBill(object ...*Bill) {
this.Bill = object
}
func (this *CpaGenBillManagerImpl) GenBill(req GenBillReq) (*GenBillResp, error) {
this.Append(NewCpaCostQueryVisitor[*CpaGenBillManagerImpl](req))
this.Append(NewCpaGenBillVisitor[*CpaGenBillManagerImpl]())
err := this.Exec(this)
if err != nil {
return nil, err
}
resp := new(GenBillResp)
resp.Data = this.Bill
return resp, nil
}

func NewCpaGenSettleManagerImpl() *CpaGenSettleManagerImpl {
object := new(CpaGenSettleManagerImpl)
object.AbstractManager = NewAbstractManager[*CpaGenSettleManagerImpl]()
return object
}

type CpaGenSettleManagerImpl struct {
*AbstractManager[*CpaGenSettleManagerImpl]
Bill []*Bill
Settle []*Settle
}

func (this *CpaGenSettleManagerImpl) ListBill() []*Bill {
return this.Bill
}
func (this *CpaGenSettleManagerImpl) SetBill(object ...*Bill) {
this.Bill = object
}
func (this *CpaGenSettleManagerImpl) ListSettle() []*Settle {
return this.Settle
}
func (this *CpaGenSettleManagerImpl) SetSettle(object ...*Settle) {
this.Settle = object
}
func (this *CpaGenSettleManagerImpl) GenSettle(req GenSettleReq) (*GenSettleResp, error) {
this.Append(NewCpaBillQueryVisitor[*CpaGenSettleManagerImpl](req))
this.Append(NewAsyncVisitor[*CpaGenSettleManagerImpl]())
this.Append(NewGenSettleVisitor[*CpaGenSettleManagerImpl]())
err := this.Exec(this)
if err != nil {
return nil, err
}
resp := new(GenSettleResp)
resp.Data = this.Settle
return resp, nil
}

func NewCpaCostQueryVisitor[Manager CpaCostQueryManager](req GenBillReq) *CpaCostQueryVisitor[Manager] {
object := new(CpaCostQueryVisitor[Manager])
object.AbstractVisitor = NewAbstractVisitor[Manager]()
object.Req = req
return object
}

type CpaCostQueryManager interface {
SetCost(object ...*CpaCost)
}

type CpaCostQueryVisitor[Manager CpaCostQueryManager] struct {
*AbstractVisitor[Manager]
Req GenBillReq
}

func (this *CpaCostQueryVisitor[Manager]) Exec(manager Manager) error {
fmt.Printf("使用GenBillReq查询CPA消耗: %+v\n", this.Req)
cost := make([]*CpaCost, this.Req.Len)
for i := range cost {
cost[i] = new(CpaCost)
}
manager.SetCost(cost...)
return this.ExecNext(manager)
}

func NewCpaGenBillVisitor[Manager CpaGenBillManager]() *CpaGenBillVisitor[Manager] {
object := new(CpaGenBillVisitor[Manager])
object.AbstractVisitor = NewAbstractVisitor[Manager]()
return object
}

type CpaGenBillManager interface {
ListCost() []*CpaCost
SetBill(object ...*Bill)
}

type CpaGenBillVisitor[Manager CpaGenBillManager] struct {
*AbstractVisitor[Manager]
}

func (this *CpaGenBillVisitor[Manager]) Exec(manager Manager) error {
cost := manager.ListCost()
fmt.Printf("使用CpaCost生成CPA对账单: %+v\n", cost)
list := make([]interface{}, len(cost))
for i := range cost {
list[i] = cost[i]
}
bill := GenBill(list...)
manager.SetBill(bill...)
return this.ExecNext(manager)
}

func NewCpaBillQueryVisitor[Manager CpaBillQueryManager](req GenSettleReq) *CpaBillQueryVisitor[Manager] {
object := new(CpaBillQueryVisitor[Manager])
object.AbstractVisitor = NewAbstractVisitor[Manager]()
object.Req = req
return object
}

type CpaBillQueryManager interface {
SetBill(object ...*Bill)
}

type CpaBillQueryVisitor[Manager CpaBillQueryManager] struct {
*AbstractVisitor[Manager]
Req GenSettleReq
}

func (this *CpaBillQueryVisitor[Manager]) Exec(manager Manager) error {
fmt.Printf("使用GenSettleReq查询符合CPA要求的对账单: %+v\n", this.Req)
bill := make([]*Bill, this.Req.Len)
for i := range bill {
bill[i] = new(Bill)
}
manager.SetBill(bill...)
return this.ExecNext(manager)
}

//ad

func NewAdGenBillManagerImpl() *AdGenBillManagerImpl {
object := new(AdGenBillManagerImpl)
object.AbstractManager = NewAbstractManager[*AdGenBillManagerImpl]()
return object
}

type AdGenBillManagerImpl struct {
*AbstractManager[*AdGenBillManagerImpl]
Cost []*AdCost
Bill []*Bill
}

func (this *AdGenBillManagerImpl) ListCost() []*AdCost {
return this.Cost
}
func (this *AdGenBillManagerImpl) SetCost(object ...*AdCost) {
this.Cost = object
}
func (this *AdGenBillManagerImpl) ListBill() []*Bill {
return this.Bill
}
func (this *AdGenBillManagerImpl) SetBill(object ...*Bill) {
this.Bill = object
}
func (this *AdGenBillManagerImpl) GenBill(req GenBillReq) (*GenBillResp, error) {
this.Append(NewAdCostQueryVisitor[*AdGenBillManagerImpl](req))
this.Append(NewAdGenBillVisitor[*AdGenBillManagerImpl]())
err := this.Exec(this)
if err != nil {
return nil, err
}
resp := new(GenBillResp)
resp.Data = this.Bill
return resp, nil
}

func NewAdGenSettleManagerImpl() *AdGenSettleManagerImpl {
object := new(AdGenSettleManagerImpl)
object.AbstractManager = NewAbstractManager[*AdGenSettleManagerImpl]()
return object
}

type AdGenSettleManagerImpl struct {
*AbstractManager[*AdGenSettleManagerImpl]
Bill []*Bill
Settle []*Settle
}

func (this *AdGenSettleManagerImpl) ListBill() []*Bill {
return this.Bill
}
func (this *AdGenSettleManagerImpl) SetBill(object ...*Bill) {
this.Bill = object
}
func (this *AdGenSettleManagerImpl) ListSettle() []*Settle {
return this.Settle
}
func (this *AdGenSettleManagerImpl) SetSettle(object ...*Settle) {
this.Settle = object
}
func (this *AdGenSettleManagerImpl) GenSettle(req GenSettleReq) (*GenSettleResp, error) {
this.Append(NewAdBillQueryVisitor[*AdGenSettleManagerImpl](req))
this.Append(NewAsyncVisitor[*AdGenSettleManagerImpl]())
this.Append(NewGenSettleVisitor[*AdGenSettleManagerImpl]())
err := this.Exec(this)
if err != nil {
return nil, err
}
resp := new(GenSettleResp)
resp.Data = this.Settle
return resp, nil
}

func NewAdCostQueryVisitor[Manager AdCostQueryManager](req GenBillReq) *AdCostQueryVisitor[Manager] {
object := new(AdCostQueryVisitor[Manager])
object.AbstractVisitor = NewAbstractVisitor[Manager]()
object.Req = req
return object
}

type AdCostQueryManager interface {
SetCost(object ...*AdCost)
}

type AdCostQueryVisitor[Manager AdCostQueryManager] struct {
*AbstractVisitor[Manager]
Req GenBillReq
}

func (this *AdCostQueryVisitor[Manager]) Exec(manager Manager) error {
fmt.Printf("使用GenBillReq查询AD消耗: %+v\n", this.Req)
cost := make([]*AdCost, this.Req.Len)
for i := range cost {
cost[i] = new(AdCost)
}
manager.SetCost(cost...)
return this.ExecNext(manager)
}

func NewAdGenBillVisitor[Manager AdGenBillManager]() *AdGenBillVisitor[Manager] {
object := new(AdGenBillVisitor[Manager])
object.AbstractVisitor = NewAbstractVisitor[Manager]()
return object
}

type AdGenBillManager interface {
ListCost() []*AdCost
SetBill(object ...*Bill)
}

type AdGenBillVisitor[Manager AdGenBillManager] struct {
*AbstractVisitor[Manager]
}

func (this *AdGenBillVisitor[Manager]) Exec(manager Manager) error {
cost := manager.ListCost()
fmt.Printf("使用AdCost生成AD对账单: %+v\n", cost)
list := make([]interface{}, len(cost))
for i := range cost {
list[i] = cost[i]
}
bill := GenBill(list...)
manager.SetBill(bill...)
return this.ExecNext(manager)
}

func NewAdBillQueryVisitor[Manager AdBillQueryManager](req GenSettleReq) *AdBillQueryVisitor[Manager] {
object := new(AdBillQueryVisitor[Manager])
object.AbstractVisitor = NewAbstractVisitor[Manager]()
object.Req = req
return object
}

type AdBillQueryManager interface {
SetBill(object ...*Bill)
}

type AdBillQueryVisitor[Manager AdBillQueryManager] struct {
*AbstractVisitor[Manager]
Req GenSettleReq
}

func (this *AdBillQueryVisitor[Manager]) Exec(manager Manager) error {
fmt.Printf("使用GenSettleReq查询符合AD要求的对账单: %+v\n", this.Req)
bill := make([]*Bill, this.Req.Len)
for i := range bill {
bill[i] = new(Bill)
}
manager.SetBill(bill...)
return this.ExecNext(manager)
}

最近关于访问者模式的一些设计
https://cellargalaxy.github.io/posts/设计模式/1.最近关于访问者模式的一些设计/
作者
cellargalaxy
发布于
2023年12月31日
许可协议