✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。
🍎个人主页:Meteors.的博客
💞当前专栏:设计模式
✨特色专栏:知识分享
🥭本文内容:23种设计模式------代理模式(Proxy Pattern)
📚 ** ps ** :阅读文章如果有问题或者疑惑,欢迎在评论区提问或指出。
目录
[一. 背景](#一. 背景)
[二. 介绍](#二. 介绍)
[三. 核心概念](#三. 核心概念)
[四. 实际应用示例](#四. 实际应用示例)
[1. 图片加载代理](#1. 图片加载代理)
[2. 权限控制代理](#2. 权限控制代理)
[3. 网络请求代理](#3. 网络请求代理)
[4. 缓存代理](#4. 缓存代理)
[五. 代理模式的类型](#五. 代理模式的类型)
[六. 代理模式的优势](#六. 代理模式的优势)
[七. 注意事项](#七. 注意事项)
[八. 总结](#八. 总结)
一. 背景
也行此时你还感觉不到代理模式是多么的好用,我慢慢帮你剖析吧!
不知道读者对于Java的Spring AOP(方法粒度的面向切面编程)是否了解?其实代理模式可以类比成一种对象粒度的AOP。在我们在项目中创建一个对象的时候,如果还要添加类似于日志、判断前置条件(如android中的用户是否允许某种权限)、或者进行缓存判断(类似Redis)的操作,如果这个时候如果都把代码写成一团,功能肯定也可以实现,但是代码会显得非常冗余,这个时候代理模式的优势就体现出来了,让我们一起来揭开它的面纱!
二. 介绍
代理模式(Proxy Pattern) 是面向对象设计模式中的一种结构型模式 。它为其他对象提供一种代理以控制对这个对象的访问。代理模式在客户端和目标对象之间起到中介作用,可以在不改变目标对象的情况下,增加额外的功能操作(知道是结构型和可以添加功能就够了~)。
三. 核心概念
在代理模式中,通常涉及三个角色:
抽象主题(Subject): 声明了真实主题和代理主题的共同接口***(++方法功能提到接口++)***
真实主题(RealSubject): 定义了代理主题所代表的真实对象***(++原本要New的对象++)***
代理主题(Proxy): 保存一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口***(++完成延迟加载和添加日志等功能,后面使用对象的时候只要创建这个对象就够了++)***
四. 实际应用示例
1. 图片加载代理
在Android应用中,我们经常需要加载网络图片。为了提高性能,可以使用代理模式来实现图片的延迟加载:
java// 抽象接口 public interface Image { void display(); } // 真实主题 - 真实图片 public class RealImage implements Image { private String filename; public RealImage(String filename) { this.filename = filename; loadFromDisk(); } private void loadFromDisk() { System.out.println("从磁盘加载图片: " + filename); // 模拟耗时操作 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void display() { System.out.println("显示图片: " + filename); } } // 代理主题 - 图片代理 public class ImageProxy implements Image { private RealImage realImage; private String filename; public ImageProxy(String filename) { this.filename = filename; } @Override public void display() { if (realImage == null) { realImage = new RealImage(filename); } realImage.display(); } } // 使用示例 public class MainActivity { public void onCreate() { // 创建代理对象,不会立即加载图片 Image image = new ImageProxy("photo.jpg"); // 只有在需要显示时才真正加载图片 image.display(); // 此时才加载并显示图片 } }
这种方式可以有效减少内存使用,只有在真正需要显示图片时才加载,提高了应用性能。
2. 权限控制代理
在Android应用中,某些功能需要特定权限才能访问,可以使用代理模式进行权限检查:
java// 抽象接口 public interface Camera { void takePhoto(); void recordVideo(); } // 真实主题 - 相机功能实现 public class RealCamera implements Camera { @Override public void takePhoto() { System.out.println("拍照成功"); } @Override public void recordVideo() { System.out.println("开始录像"); } } // 代理主题 - 带权限检查的相机代理 public class CameraPermissionProxy implements Camera { private RealCamera realCamera; private Context context; public CameraPermissionProxy(Context context) { this.context = context; } @Override public void takePhoto() { if (checkCameraPermission()) { if (realCamera == null) { realCamera = new RealCamera(); } realCamera.takePhoto(); } else { System.out.println("没有相机权限,无法拍照"); } } @Override public void recordVideo() { if (checkCameraPermission()) { if (realCamera == null) { realCamera = new RealCamera(); } realCamera.recordVideo(); } else { System.out.println("没有相机权限,无法录像"); } } private boolean checkCameraPermission() { // 检查相机权限 return ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED; } } // 使用示例 public class CameraActivity { private Camera camera; public void onCreate() { camera = new CameraPermissionProxy(this); } public void onTakePhotoClick() { camera.takePhoto(); // 自动检查权限 } }
3. 网络请求代理
在网络请求中,可以使用代理模式添加日志、缓存等功能:
java// 抽象接口 public interface HttpClient { String get(String url); String post(String url, String data); } // 真实主题 - 真实的HTTP客户端 public class RealHttpClient implements HttpClient { @Override public String get(String url) { // 模拟网络请求 System.out.println("发送GET请求到: " + url); return "Response from " + url; } @Override public String post(String url, String data) { System.out.println("发送POST请求到: " + url + " 数据: " + data); return "Response from " + url; } } // 代理主题 - 带日志功能的HTTP客户端代理 public class LoggingHttpClientProxy implements HttpClient { private RealHttpClient realHttpClient; private boolean enableLogging; public LoggingHttpClientProxy(boolean enableLogging) { this.enableLogging = enableLogging; } @Override public String get(String url) { long startTime = System.currentTimeMillis(); if (realHttpClient == null) { realHttpClient = new RealHttpClient(); } if (enableLogging) { System.out.println("开始GET请求: " + url); } String result = realHttpClient.get(url); if (enableLogging) { long endTime = System.currentTimeMillis(); System.out.println("GET请求完成,耗时: " + (endTime - startTime) + "ms"); } return result; } @Override public String post(String url, String data) { long startTime = System.currentTimeMillis(); if (realHttpClient == null) { realHttpClient = new RealHttpClient(); } if (enableLogging) { System.out.println("开始POST请求: " + url); } String result = realHttpClient.post(url, data); if (enableLogging) { long endTime = System.currentTimeMillis(); System.out.println("POST请求完成,耗时: " + (endTime - startTime) + "ms"); } return result; } } // 使用示例 public class NetworkManager { private HttpClient httpClient; public NetworkManager() { // 开发环境启用日志 boolean isDebug = true; httpClient = new LoggingHttpClientProxy(isDebug); } public void fetchData() { String result = httpClient.get("https://api.example.com/data"); System.out.println("获取到数据: " + result); } }
4. 缓存代理
在数据访问中,代理模式可以用来实现缓存机制:
java// 抽象接口 public interface DataService { String getData(String key); } // 真实主题 - 真实的数据服务 public class RealDataService implements DataService { @Override public String getData(String key) { // 模拟从数据库或网络获取数据 System.out.println("从数据库获取数据,键: " + key); try { Thread.sleep(1000); // 模拟耗时操作 } catch (InterruptedException e) { e.printStackTrace(); } return "Data for " + key; } } // 代理主题 - 带缓存功能的数据服务代理 public class CachedDataServiceProxy implements DataService { private RealDataService realDataService; private Map<String, String> cache = new HashMap<>(); @Override public String getData(String key) { // 先检查缓存 if (cache.containsKey(key)) { System.out.println("从缓存获取数据,键: " + key); return cache.get(key); } // 缓存未命中,从真实服务获取 if (realDataService == null) { realDataService = new RealDataService(); } String data = realDataService.getData(key); cache.put(key, data); // 存入缓存 System.out.println("数据已缓存,键: " + key); return data; } public void clearCache() { cache.clear(); System.out.println("缓存已清空"); } } // 使用示例 public class DataRepository { private DataService dataService = new CachedDataServiceProxy(); public void displayData(String key) { // 第一次调用 String data1 = dataService.getData(key); System.out.println("第一次获取: " + data1); // 第二次调用(从缓存获取) String data2 = dataService.getData(key); System.out.println("第二次获取: " + data2); } }
五. 代理模式的类型
代理模式还可以根据作用,分为下面几种类型:
**远程代理(Remote Proxy):**为一个位于不同地址空间的对象提供本地代表。
**虚拟代理(Virtual Proxy):**根据需要创建开销很大的对象。
**保护代理(Protection Proxy):**控制对原始对象的访问,常用于对象应该有不同的访问权限时。
**智能引用(Smart Reference):**取代简单的指针,在访问对象时执行一些附加操作。
六. 代理模式的优势
延迟加载: 虚拟代理可以实现对象的延迟初始化,节省系统资源
权限控制: 保护代理可以在访问真实对象前进行权限检查
功能增强: 可以在不修改原始类的情况下添加额外功能(如日志、缓存等)
远程访问: 远程代理可以隐藏网络通信的复杂性
**对象访问控制:**可以控制对昂贵资源的访问
七. 注意事项
性能开销: 代理模式会增加系统的复杂性和可能的性能开销
代码复杂性: 引入代理会增加类的数量,使系统更加复杂
调试困难: 代理模式可能使调试变得更加困难
**合理使用:**不是所有场景都需要代理,应根据实际需求选择
八. 总结
代理模式是开发中非常实用的设计模式,它可以在不改变原有代码结构的情况下,为对象提供额外的功能。通过合理使用代理模式,我们可以实现延迟加载、权限控制、日志记录、缓存等功能,提高应用的性能和用户体验。
在实际开发中,我们可以根据具体需求选择合适的代理类型,如虚拟代理用于延迟加载,保护代理用于权限控制,智能引用代理用于添加额外功能等。正确使用代理模式可以让我们的代码更加优雅、高效和易于维护!
最后,
其它设计模式会陆续更新,希望文章对你有所帮助!