大家好,我是晴天,本周我们又见面了。本周有点发烧感冒,更文有点慢了,请大家见谅。言归正传,本周我们继续一起学习一文搞懂设计模式系列文章之代理模式。

一文搞懂设计模式之代理模式_设计模式

什么是代理模式

我们先来看看 GoF 对代理模式的定义:

Provide a surrogate or placeholder for another object to control access to it. ——— GoF
即:代理模式为一个对象提供一种代理以控制对该对象的访问。

代理模式属于结构型设计模式,它能够代替客户向服务提供者发起请求,并且可以在请求服务提供者的前后做一些其他方面的处理。

为了便于我们的理解,接下来借助一个具体的场景理解代理模式。

场景

假设你很喜欢海外购物,喜欢购买韩国的化妆品,喜欢购买美国的生鱼片。在没有代理商的年代里,你只能亲自飞到韩国卖化妆品的店去购买化妆品,飞到美国的生鱼片店去购买生鱼片。你买完这些商品之后,回国进海关的时候,你还需要接受安检并依法补交税款,然后你才能带着这些商品回家享用。这一整个过程是相当费时而且繁琐的,每次你都难免会为出海购物而感都头疼。这时候,一个名叫“胖墩墩”的代理商出现了,他能够去韩国买对应的化妆品、去美国买你要的生鱼片并通过海关的安检带回国,然后向你出售韩国化妆品和美国生鱼片,这样就不需要你亲自出国购买而且也不需要你过海关安检,你只需要付钱给“胖墩墩”,然后在家等着收货就行了。

从这个场景中,我们看到,代理去韩国买了你想要的化妆品,去美国买了你喜欢的生鱼片,并且通过海关带回了祖国,你只需要付钱给代理,就可以在家等着收货了。我们现在就可以清晰代理是什么了,代理能够代替服务提供商(韩国化妆品店和美国生鱼片店)向你提供服务,并且还能够额外提供更多的服务(通过海关安检交税),因此在你看来,跟代理买东西和直接跟服务提供商买东西无异。

为什么需要代理模式

一文搞懂设计模式之代理模式_业务逻辑_02


我们来看一下代理模式的类图

首先定义一个抽象的服务提供商 shopping,它能够提供 Buy(good)购买商品的方法,它的子类有具体的韩国服务提供商和美国服务提供商,以及代理商,都需要实现 Buy(good)方法,代理商还有一个CheckIn(good)的额外方法,用于海关安检,代理商需要依赖于具体的服务提供商(韩国服务提供商和美国服务提供商)。客户端可以直接跟接口进行交互。

通过上面的场景,这个问题就很好说明了。

  1. 代理可以把原始的服务提供商封装起来,向我们提供服务
  2. 代理可以提供额外更强劲的功能
  3. 代理的使用方法和原始服务提供商无异

如何使用代理模式

下面我们把上面的场景写成代码,一起来学习一下

package main

import "fmt"

// 代理模式
// 定义需要购买的商品的结构
type Good struct {
	Name     string
	Producer string
}

// 抽象层
// 服务提供商的抽象化定义   向我们提供Buy(good) 方法
type Shopping interface {
	Buy(good Good)
}

// 实现层
// 韩国购物
type KoreaShopping struct {
}

func (k *KoreaShopping) Buy(good Good) {
	fmt.Println("购买了一件韩国商品:", good.Name)
}

// 美国购物
type AmericaShopping struct {
}

func (a *AmericaShopping) Buy(good Good) {
	fmt.Println("购买了一件美国商品:", good.Name)
}

// 代理类,用于封装韩国购物和美国购物对象
type ShoppingProxy struct {
	// 继承抽象结构,用于后续传入具体韩国购物对象和美国购物对象,从而实现多态功能
	shopping Shopping
}

func NewShoppingProxy(shopping Shopping) ShoppingProxy {
	return ShoppingProxy{
		shopping: shopping,
	}
}

func (s *ShoppingProxy) Buy(good Good) {
	s.shopping.Buy(good)
	s.CheckIn(good)
}

func (s *ShoppingProxy) CheckIn(good Good) {
	if good.Producer == "america" {
		fmt.Printf("对美国购买的商品:%v,缴税并加征%v关税\n", good.Name, "120%")
	} else if good.Producer == "korea" {
		fmt.Printf("对韩国购买的商品:%v,缴税并加征%v关税\n", good.Name, "100%")
	}
}

// 业务逻辑层
func main() {
	g1 := Good{
		Name:     "韩国化妆品",
		Producer: "korea",
	}
	g2 := Good{
		Name:     "美国生鱼片",
		Producer: "america",
	}
	k_shopping := &KoreaShopping{}
	var shopping ShoppingProxy
	shopping = NewShoppingProxy(k_shopping)
	shopping.Buy(g1)
	a_shopping := &AmericaShopping{}
	shopping = NewShoppingProxy(a_shopping)
	shopping.Buy(g2)
}


/*
  输出结果:
  购买了一件韩国商品: 韩国化妆品
  对韩国购买的商品:韩国化妆品,加征100%关税
  购买了一件美国商品: 美国生鱼片
  对美国购买的商品:美国生鱼片,加征120%关税
*/
代码解释:

我们定义了抽象服务提供商 shopping,也定义了具体的服务提供商 koreaShopping 和 AmericaShopping 以及代理ShoppingProxy,他们都实现了Buy(good)方法,代理还额外增加了CheckIn(good Good)方法,用于海关安检。在业务逻辑层,定义了两种商品(韩国化妆品和美国生鱼片),实例化了具体的韩国服务提供商和美国服务提供商,并传入代理中,用于代理对他们进行管理。

代理模式的优点:
  1. 能够一定程度上实现业务逻辑和具体的服务提供商的解耦,协调服务调用者和服务提供商之间的关系
  2. 业务逻辑层可以面向接口编程,符合开闭原则,扩展起来比较方便
代理模式的缺点:
  1. 代理类比较复杂庞大,所有实现的逻辑都堆叠在代理类中,不方便维护。

总结

本文,我们一起学习了什么是代理模式以及为什么需要代理模式,通俗一点理解,代理就是能够对具体的服务对象进行统一管理,并且代替服务对象向我们提供服务,我们请求服务时,只需要向代理请求即可,无需直接向具体的服务对象请求服务,此外代理还可以增加一些其他功能为我们提供更强的服务。

写在最后

感谢大家的阅读,晴天将继续努力,分享更多有趣且实用的主题,如有错误和纰漏,欢迎留言给予指正。 更多文章敬请关注作者个人公众号 晴天码字。 我们下期不见不散,to be continued…