当前位置: 首页 > article >正文

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

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

代理模式-本文目录

什么是代理模式

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

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

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

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

场景

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

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

为什么需要代理模式

代理模式类图
我们来看一下代理模式的类图
首先定义一个抽象的服务提供商 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…


http://www.kler.cn/a/132474.html

相关文章:

  • JavaScript 原型
  • 华为云租户网络-用的是隧道技术
  • SpringBoot中Maven的定义及国内源配置教程,实现自动获取Jar包
  • Java putIfAbsent() 详解
  • android framework ams/wms常见系统日志(main\system\events\crash,protoLog使用)
  • Oracle 单机及 RAC 环境 归档模式及路径修改
  • AIGC创作系统ChatGPT源码,AI绘画源码,支持最新GPT-4-Turbo模型,支持DALL-E3文生图
  • “开源 vs. 闭源:大模型的未来发展趋势预测“——探讨大模型未来的发展方向
  • 2023版Idea创建JavaWeb时,右键new没有Servlet快捷键选项
  • Linux输入设备应用编程(键盘,按键,触摸屏,鼠标)
  • 电子画册真的好好用,制作也简单,都快来学学!
  • Springboot集成JDBC
  • V100 配置 Scanpy + Scvi + Pytorch
  • 快速搜索多个word、excel等文件中内容
  • Element UI 偶发性图标乱码问题
  • flutter web 中嵌入一个html
  • 基于单片机体温脉搏检测控制系统及源程序
  • 【OpenGauss源码学习 —— 执行算子(Append算子)】
  • 【Linux】vimrc 配置方案
  • springboot项目中没有识别到yml文件解决办法
  • 【机器学习】朴素贝叶斯算法:多项式、高斯、伯努利,实例应用(心脏病预测)
  • AlphaControls控件TsDBCombobox出错:访问违规
  • 腾讯云服务器怎么买便宜?腾讯云服务器新人专享限时特惠购买链接
  • 为RabbitMQ配置SSL
  • 【10套模拟】【6】
  • Linux 终端 Ctrl + C 无法终止当前程序(详细解决步骤)