Dawn's Blogs

分享技术 记录成长

0%

Easy搞定Golang设计模式 (4) 结构型模式之代理模式 装饰模式"

代理模式

代理模式就是为对象提供一个代理,这个代理可以控制对这个对象的访问。这个代理又投了额外添加的功能,同样也符合开闭原则,因为原来对象并不会改变只会增加代理的功能。

代理中的角色和职责如下:

抽象主题角色:真实主题和代理主题的共同接口。

真实主题角色:代理角色所代理的真实对象,实现了抽象主题接口。

代理主题角色:包含对真实主题角色的引用,代理也实现了抽象主题接口,代理在执行真实主题之前或者之后又进行了一些操作。

image-20230418202707559

案例

比如购物作为一个主题任务,这是一个抽象的主题。那么真实的主题包括韩国购物、美国购物等。那么海外代购就算是这些主题的代理,代理在去购物之前还需要辨别真假,接着购物,最后进行海关安检等。

image-20230418204443811

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
type Goods struct {
Kind string //商品种类
Fact bool //商品真伪
}

// =========== 抽象层 ===========
//抽象的购物主题Subject
type Shopping interface {
Buy(goods *Goods) //某任务
}

// =========== 实现层 ===========
//具体的购物主题, 实现了shopping, 去韩国购物
type KoreaShopping struct {}

func (ks *KoreaShopping) Buy(goods *Goods) {
fmt.Println("去韩国进行了购物, 买了 ", goods.Kind)
}


//具体的购物主题, 实现了shopping, 去美国购物
type AmericanShopping struct {}

func (as *AmericanShopping) Buy(goods *Goods) {
fmt.Println("去美国进行了购物, 买了 ", goods.Kind)
}

//海外的代理
type OverseasProxy struct {
shopping Shopping //代理某个主题,这里是抽象类型
}

func (op *OverseasProxy) Buy(goods *Goods) {
// 1. 先验货
if (op.distinguish(goods) == true) {
//2. 进行购买
op.shopping.Buy(goods) //调用原被代理的具体主题任务
//3 海关安检
op.check(goods)
}
}

//创建一个代理,并且配置关联被代理的主题
func NewProxy(shopping Shopping) Shopping {
return &OverseasProxy{shopping}
}

//验货流程
func (op *OverseasProxy) distinguish(goods *Goods) bool {
fmt.Println("对[", goods.Kind,"]进行了辨别真伪.")
if (goods.Fact == false) {
fmt.Println("发现假货",goods.Kind,", 不应该购买。")
}
return goods.Fact
}

//安检流程
func (op *OverseasProxy) check(goods *Goods) {
fmt.Println("对[",goods.Kind,"] 进行了海关检查, 成功的带回祖国")
}

func main() {
g1 := Goods{
Kind: "韩国面膜",
Fact: true,
}

g2 := Goods{
Kind: "CET4证书",
Fact: false,
}

var shopping Shopping
shopping = new(KoreaShopping)

fmt.Println("---------------以下是 使用 代理模式-------")
var overseasProxy Shopping
overseasProxy = NewProxy(shopping)
overseasProxy.Buy(&g1)
overseasProxy.Buy(&g2)
}

装饰模式

装饰模式可以动态的给对象增加一些功能,这样比生成子类实现更加灵活。

装饰模式的角色和职责如下:

  • 抽象构件:它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。
  • 具体构件:它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。

image-20230418205018308

案例

手机抽象构件(Phone 类),可以为手机装手机壳(装饰器类)以及贴膜(装饰器类)。

image-20230418205231512

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
// ---------- 抽象层 ----------
//抽象的构件
type Phone interface {
Show() //构件的功能
}

//装饰器基础类(该类本应该为interface,但是Golang interface语法不可以有成员属性)
type Decorator struct {
phone Phone
}

func (d *Decorator) Show() {}


// ----------- 实现层 -----------
// 具体的构件
type HuaWei struct {}

func (hw *HuaWei) Show() {
fmt.Println("秀出了HuaWei手机")
}

type XiaoMi struct{}

func (xm *XiaoMi) Show() {
fmt.Println("秀出了XiaoMi手机")
}

// 具体的装饰器类
type MoDecorator struct {
Decorator //继承基础装饰器类(主要继承Phone成员属性)
}

func (md *MoDecorator) Show() {
md.phone.Show() //调用被装饰构件的原方法
fmt.Println("贴膜的手机") //装饰额外的方法
}

func NewMoDecorator(phone Phone) Phone {
return &MoDecorator{Decorator{phone}}
}

type KeDecorator struct {
Decorator //继承基础装饰器类(主要继承Phone成员属性)
}

func (kd *KeDecorator) Show() {
kd.phone.Show()
fmt.Println("手机壳的手机") //装饰额外的方法
}

func NewKeDecorator(phone Phone) Phone {
return &KeDecorator{Decorator{phone}}
}


// ------------ 业务逻辑层 ---------
func main() {
var huawei Phone
huawei = new(HuaWei)
huawei.Show() //调用原构件方法

fmt.Println("---------")
//用贴膜装饰器装饰,得到新功能构件
var moHuawei Phone
moHuawei = NewMoDecorator(huawei) //通过HueWei ---> MoHuaWei
moHuawei.Show() //调用装饰后新构件的方法

fmt.Println("---------")
var keHuawei Phone
keHuawei = NewKeDecorator(huawei) //通过HueWei ---> KeHuaWei
keHuawei.Show()

fmt.Println("---------")
var keMoHuaWei Phone
keMoHuaWei = NewMoDecorator(keHuawei) //通过KeHuaWei ---> KeMoHuaWei
keMoHuaWei.Show()
}