设计模式之代理模式(Proxy)(2)
代理模式是为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用,其特征是代理类与委托类有同样的接口。
动机:
在软件设计中,使用代理模式的意图也很多,比如因为安全原因需要屏蔽客户端直接访问真实对象,或者在远程调用中需要使用代理类处理远程方法调用的技术细节 (如 RMI),也可能为了提升系统性能,通过控制来延迟对象的创建和实例化,直到真正需要使用该对象才进行创建和实例化。
由于一些对象创建和实例化需要占用大量系统资源,但我们并不能确定用户一定会调用该对象,所以通过延迟对象实例化来减缓系统资源的消耗。例如文档编辑器如word,我们可以在里面插入链接、图片等,但是并不是我们每次打开word时都有创建和实例化这些对象,特别是实例化图片对象很消耗资源,并不需要实例化所有图片。当我们在查看word时,只是看到其中的一部分,所以没有必要实例化所以资源,当我们看下一页时再实例化也不迟。
类型:结构类模式
类图:
图1 代理模式类图
代理模式角色:
1) 主题接口:定义代理类和真实主题的公共对外方法,也是代理类代理真实主题的方法;
2) 真实主题:真正实现业务逻辑的类;
3) 代理类:用来代理和封装真实主题;
4) Main:客户端,使用代理类和主题接口完成一些工作。
优点:
- 对客户端来说,隐藏了真实对象的细节及复杂性。
- 将代理对象与真正被调用的对象分离,在一定程度上降低了系统的耦合度。
- 在客户端和目标对象之间起到一个中介作用,这样可以起到保护目标对象的作用,也可以对目标对象调用之前进行其他操作。
- 远程代理使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的性能与处理速度,可以快速响应并处理客户端请求。
- 虚拟代理通过使用一个小对象来代表一个大对象,可以减少系统资源的消耗,对系统进行优化并提高运行速度。
- 安全代理可以控制对真实对象的使用权限。
缺点:
- 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。
- 增加了系统的复杂度。
适用场景
1) 远程代理:也就是为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。比如说 WebService,当我们在应用程序的项目中加入一个 Web 引用,引用一个 WebService,此时会在项目中声称一个 WebReference 的文件夹和一些文件,这个就是起代理作用的,这样可以让那个客户端程序调用代理解决远程访问的问题。还有.NET的WCF的远程代理。
2) 虚拟代理:是根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象。这样就可以达到性能的最优化,比如打开一个网页,这个网页里面包含了大量的文字和图片,但我们可以很快看到文字,但是图片却是一张一张地下载后才能看到,那些未打开的图片框,就是通过虚拟代理来替换了真实的图片,此时代理存储了真实图片的路径和尺寸。
3) 安全代理:用来控制真实对象访问时的权限。一般用于对象应该有不同的访问权限的时候。
4) 指针引用:是指当调用真实的对象时,代理处理另外一些事。比如计算真实对象的引用次数,这样当该对象没有引用时,可以自动释放它,或当第一次引用一个持久对象时,将它装入内存,或是在访问一个实际对象前,检查是否已经释放它,以确保其他对象不能改变它。这些都是通过代理在访问一个对象时附加一些内务处理。
5) 智能指引:当调用真实对象时,代理提供一些额外的操作。如将对象被操作的次数记录起来等。
6) 延迟加载,用代理模式实现延迟加载的一个经典应用就在 Hibernate 框架里面。当 Hibernate 加载实体 bean 时,并不会一次性将数据库所有的数据都装载。默认情况下,它会采取延迟加载的机制,以提高系统的性能。Hibernate 中的延迟加载主要分为属性的延迟加载和关联表的延时加载两类。实现原理是使用代理拦截原有的 getter 方法,在真正使用对象数据时才去数据库或者其他第三方组件加载实际的数据,从而提升系统性能。
7) 缓冲代理:为某一个目标操作提供临时的存储空间,以便更多客户端共享此结果。
8) 防火墙代理:保护目标不让恶意用户接近。
9) 同步化代理:使几个用户能同时使用一个对象而没有冲突。
代理模式分类
1. 静态代理(静态定义代理类,自己静态定义的代理类)
1)优点:
可以做到在不修改目标对象的功能前提下,对目标功能扩展。
2)缺点:
因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多。同时,一旦接口增加方法,目标对象与代理对象都要维护。
3)静态代理模式角色:
- 抽象角色:指代理角色和真实角色对外提供的公共方法,一般为一个接口。
- 真实角色:需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用,真正的业务逻辑在此。
- 代理角色:需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。将统一的流程控制都放到代理角色中处理。
代码实现:
JAVA
//接口
public interface IClient {
void appeal();//谈判
}
/**
* 接口实现
* 目标对象
*/
public class Client implements IClient {
public void appeal()
{
System.out.println("委托人谈判"); }
}
/**
* 代理对象,静态代理
*/
public class ClientProxy implements IClient {
private Client client;
public ClientProxy(Client client)
{
this.client=client;
}
public void appeal()
{
System.out.println("代理谈判开始!");
client.appeal();
System.out.println("代理谈判结束!");
}
}
public class AppTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
//目标对象
Client target = new Client();
//代理对象,把目标对象传给代理对象,建立代理关系
ClientProxy proxy = new ClientProxy(target);
proxy.appeal();//执行的是代理的方法
}
}
输出结果:
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace proxyDemo
{ // 客户端调用
class Program
{
static void Main(string[] args)
{
// 创建一个代理对象并发出请求
Person proxy = new Friend();
proxy.Appeal();
Console.Read();
}
}
// 抽象主题角色
public abstract class Person
{
public abstract void Appeal();
}
//真实主题角色:委托人
public class Client : Person
{
public override void Appeal()
{
Console.WriteLine("委托人谈判中……");
}
}
// 代理角色:律师
public class Friend : Person
{
// 引用真实主题实例
Client client;
public override void Appeal()
{
Console.WriteLine("律师代理谈判……");
if (client == null)
{
client = new Client();
}
this.PreAppeal();
// 调用真实主题方法
client.Appeal();
this.PostAppeal();
}
public void PreAppeal()
{
Console.WriteLine("谈判开始~");
}
public void PostAppeal()
{
Console.WriteLine("谈判结束!");
}
}
}
输出结果:
2. 动态代理(通过程序动态生成代理类,该代理类不是自己定义的。而是由程序自动生成)
特点:
- 代理对象不需要实现接口
- 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
- 动态代理也叫做:JDK代理,接口代理
基本原理:
通过扫描被代理类的所有 public 方法,并且自动生成一个从被代理类继承的类,然后在这个生成的类中 override 这些 public 方法。这里说的自动生成,并不是生成源代码,而是直接使用中间语言(Intermedial Language)直接在内存中生成。这样在速度上和源码编译而成的中间语言相近,可以利用 Reflection Emit API 来直接生成中间语言。
代码实现:
JAVA
public interface IClient {
void appeal();//谈判
}
/**
* 接口实现
* 目标对象
*/
public class Client implements IClient {
public void appeal()
{
System.out.println("委托人谈判");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 处理器
*/
public class ClientHandler implements InvocationHandler{
private IClient client;//真实角色
/**
* 所有的流程控制都在invoke方法中
* proxy:代理类
* method:正在调用的方法
* args:方法的参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = null;
System.out.println("律师动态调用之前的处理.....");
if (method.getName().equals("appeal")) {
object = method.invoke(client, args);//激活调用的方法
}
System.out.println("律师动态调用之后的处理.....");
return object;
}
//通过构造器来初始化真实角色
public ClientHandler(IClient client) {
super();
this.client = client;
}
}
import java.lang.reflect.Proxy;
public class MainTest {
public static void main(String[] args) {
// TODO Auto-generated method stub
// 目标对象
IClient target = new Client();
// 【原始的类型 class cn.itcast.b_dynamic.UserDao】
System.out.println(target.getClass());
//处理器
ClientHandler handler = new ClientHandler(target);
// 给目标对象,创建代理对象
IClient proxy = (IClient) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{IClient.class}, handler);
// class $Proxy0 内存中动态生成的代理对象
System.out.println(proxy.getClass());
// 执行方法 【代理对象】
proxy.appeal();
}
}
输出结果:
设计模式之代理模式(Proxy)(2)的更多相关文章
- 乐在其中设计模式(C#) - 代理模式(Proxy Pattern)
原文:乐在其中设计模式(C#) - 代理模式(Proxy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 代理模式(Proxy Pattern) 作者:webabcd 介绍 为 ...
- 大熊君说说JS与设计模式之------代理模式Proxy
一,总体概要 1,笔者浅谈 当我们浏览网页时,网页中的图片有时不会立即展示出来,这就是通过虚拟代理来替代了真实的图片,而代理存储了真实图片的路径和尺寸,这就是代理方式的一种. 代理模式是比较有用途的一 ...
- 二十四种设计模式:代理模式(Proxy Pattern)
代理模式(Proxy Pattern) 介绍为其他对象提供一个代理以控制对这个对象的访问. 示例有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对 ...
- Java基础-设计模式之-代理模式Proxy
代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理 ...
- [设计模式] 12 代理模式 proxy
在GOF的<设计模式:可复用面向对象软件的基础>一书中对代理模式是这样说的:为其他对象提供一种代理以控制对这个对象的访问.结合上面的游戏代理的例子和下面的图,我们来进行分析一下.以前你是这 ...
- c#设计模式之代理模式(Proxy Pattern)
引言 代理这个词语,大家在现实世界已经频繁的接触过,例如火车站代理售票点,因为这些代理售票点的存在,我们不必要去火车站的售票处就可以查询或者取到火车票.代理点本身是没有能力生产车票的,我们在代理处享受 ...
- 设计模式三: 代理模式(Proxy) -- JDK的实现方式
简介 代理模式属于行为型模式的一种, 控制对其他对象的访问, 起到中介作用. 代理模式核心角色: 真实角色,代理角色; 按实现方式不同分为静态代理和动态代理两种; 意图 控制对其它对象的访问. 类图 ...
- 设计模式 笔记 代理模式 Proxy
//---------------------------15/04/21---------------------------- //Proxy 代理模式-----对象结构型模式 /* 1:意图: ...
- 【设计模式】—— 代理模式Proxy
前言:[模式总览]——————————by xingoo 模式意图 代理模式为其他的对象增加一个代理对象,进行访问控制.从而避免直接访问一个对象,造成效率或者安全性上的降低. 应用场景 1 远程代理, ...
- 结构型设计模式之代理模式(Proxy)
结构 意图 为其他对象提供一种代理以控制对这个对象的访问. 适用性 在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用P r o x y 模式.下面是一 些可以使用P r o x y 模式常见 ...
随机推荐
- MySQL数据备份方法
MySQL的备份和还原 备份:副本 RAID1,RAID10:保证硬件损坏而不会业务中止: DROP TABLE mydb.tb1; 备份类型: 热备份.温备份和冷备 ...
- php免杀教程【绝对原创】
.函数回调. 使用其他函数进行调用,并执行. 如:array_map('a'.'s'.'se'.'r'.'t',array($_POST['x'])); 详细教程 + 测试结果(安全狗+360主机卫士 ...
- [Swift]LeetCode680. 验证回文字符串 Ⅱ | Valid Palindrome II
Given a non-empty string s, you may delete at most one character. Judge whether you can make it a pa ...
- [Swift]LeetCode895. 最大频率栈 | Maximum Frequency Stack
Implement FreqStack, a class which simulates the operation of a stack-like data structure. FreqStack ...
- [Swift]LeetCode1001. 网格照明 | Grid Illumination
On a N x N grid of cells, each cell (x, y) with 0 <= x < N and 0 <= y < N has a lamp. In ...
- kubernetes---kubectl 管理集群资源
由于我现在的集群是把虚拟机的master文件直接拷贝过来的,所以之前的node节点是不存在的,只有k8s-ubuntu-1是新加入的,所以我要把上面之前创建的资源删除 删除deployment--&g ...
- Docker for windows : 安装Redis
一.拉取Redis镜像 docker pull hub.c..com/library/redis: 二.创建并运行Redis docker run -d -it --name redis d4f259 ...
- mysql之delete语法
一:DELETE语法 以往用delect删除表数据是都是单表(一个表)删除.对于关联表,往往都是先删除第一个表的数据,然后再写另一个delect语句删除另一个表的数据(浪费时间,又影响性能,与数据库交 ...
- Android版本号列表
Android版本号列表
- 针对 Ocelot 网关的性能测试
一.背景 目前我们项目是采用的 Ocelot 作为 API 网关,并且在其基础上结合 IdentityServer4 开发了一套 API 开放平台.由于部分项目是基于 ABP 框架进行开发的,接口的平 ...