代理模式深入(一)——静态到动态

故事

周末放假,小孙睡到12点才告别周公醒来,顿时饥肠辘辘。舍长小王正准备去食堂买饭,作为一个好舍长小王主动要帮小孙带饭。小孙点了米饭、宫保鸡丁、芬达。小孙起床洗漱,然后静待舍长。小孙心理寻思道舍长果然是好舍长啊。下面我们先把这个故事抽象一下,画作类图。这个类图即代理模式。

代理模式

定义:为其他对象提供一种代理以控制对这个对象的访问。怎么理解这句话呢?从生活的角度来说就是:用一个对象A代替另一个对象B来处理本来应该由对象B完成的事情,例如上面买饭的例子,又如通过黄牛买票等等。从代码的角度来说则是:用一个对象A来过滤、预处理对对象B的调用 。不管从哪个角度看吧,代理都需要拥有和实际对象的需要被代理的全部方法。

静态代理

类图如上所示了,定义也看了。接下来我们按照类图来看看代码。

接口(宿舍成员)

/**
 * 宿舍成员接口
 * 开发时间:2014-8-12 下午9:17:19
 */
public interface DormitoryMember {
	//买主食
    public boolean buyStapleFood(String stapleFoodName);
    //买菜
    public boolean buyDish(String dishName);
    //买饮料
    public boolean buyDrink(String drinkName);
}

代理(宿舍长)

//代理类
public class DormitoryMemberProxy implements DormitoryMember {
	//持有一个被代理的对象
    private DormitoryMember dormitoryMember;
    //构造时传入被代理对象
    public DormitoryMemberProxy(DormitoryMember dormitoryMember){
    	this.dormitoryMember=dormitoryMember;
    }
    //代理买主食
	public boolean buyStapleFood(String stapleFoodName) {
		return dormitoryMember.buyStapleFood(stapleFoodName);
	}
    //代理买菜
	public boolean buyDish(String dishName) {
		return dormitoryMember.buyDish(dishName);
	}
    //代理买饮料
	public boolean buyDrink(String drinkName) {
		return dormitoryMember.buyDrink(drinkName);
	}
}

实际类(小孙)

//实际的类
public class DormitoryMemberImpl implements DormitoryMember {
    //买主食
	public boolean buyStapleFood(String stapleFoodName) {
		try{
			System.out.println("买到主食" + stapleFoodName);
		}catch(Exception e){
			return false;
		}
		return true;
	}
    //买菜
	public boolean buyDish(String dishName) {
		try{
			System.out.println("买到菜:" + dishName);
		}catch(Exception e){
			return false;
		}
		return true;
	}
    //买饮料
	public boolean buyDrink(String drinkName) {
		try{
			System.out.println("买到饮料:" + drinkName);
		}catch(Exception e){
			return false;
		}
		return true;
	}
}

故事继续

宿舍长去到食堂买饭,结果小孙要的芬达断货了。于是宿舍长久提着米饭和菜就回去了,小孙吃着米饭和菜没有饮料难以下咽。但是,也不好说宿舍长,舍长是好舍长啊。将就的吃了午饭。时间来的晚饭时间,小孙在英雄联盟里正杀的起劲,那又闲工夫去买饭于是这工作有落到了好舍长身上。这次小孙学聪明了交代舍长说,如果有他点的东西没有了就打个电话回来在决定买什么替代。

问题来了

这里需求已经改变了,如果小孙要的东西没有了的话,要给小孙打电话以决定是不是买其他的或者不买。这个电话自然是宿舍长来打。所以我们要对代理类进行修改!这也就是使用代理模式的好处,我们关闭了对实际类的修改。代理类修改后的代码如下:

//代理类
public class DormitoryMemberProxy implements DormitoryMember {
	//持有一个被代理的对象
    private DormitoryMember dormitoryMember;
    //构造时传入被代理对象
    public DormitoryMemberProxy(DormitoryMember dormitoryMember){
    	this.dormitoryMember=dormitoryMember;
    }
    //代理买主食
	public boolean buyStapleFood(String stapleFoodName) {
		boolean buySuccess=dormitoryMember.buyStapleFood(stapleFoodName);
		if( buySuccess=false){
			System.out.println("给小孙打电话");
			return false;
		}else{
		return true;
		}
	}
    //代理买菜
	public boolean buyDish(String dishName) {
		boolean buySuccess=dormitoryMember.buyDish(dishName);
		if( buySuccess=false){
			System.out.println("给小孙打电话");
			return false;
		}else{
		return true;
		}
	}
    //代理买饮料
	public boolean buyDrink(String drinkName) {
		boolean buySuccess=dormitoryMember.buyDrink(drinkName);;
		if( buySuccess=false){
			System.out.println("给小孙打电话");
			return false;
		}else{
		return true;
		}
	}
}

问题(1)

看代码可以知道,我们要对代理类中的每一个方法都进行同样的修改。极限假设我们实现的这个接口有1000个方法,哭死都不冤枉。

问题(2)

极限假设,伟大的宿舍长不止帮小孙买饭,还要帮小李买衣服,还要帮小赵买电脑。换句话说宿舍长要代理不同的接口。但是这是不可能实现的,因为在代理类所持有的实际类是确定的,也就是说每一个代理类只能代理一个借口。

显然很不科学,这么多的代码重复出现。有不科学的情况出现,自然就会有办法因对。最怕的是没有发现问题,没有问题就没有改进。下面我们上动态代理。

动态代理

首先看问题一,既然当代理调用实际类时在代理类中的预处理都是一样的那么我们要达到代码不重复的话就只要保证调用实际类之前或者之后都回掉到某个处理就好了。当然以前好像没有学过可以对很多种不同的方法都同样回掉一个函数,因为类的参数个数和类型以及返回值都是不一致的。因此,java中就为此专门有一个接口可以实现这样的功能,InvocationHandler接口。

再看问题二,对于问题二我们必须将代理类和被代理类解耦,通常我们解决这类问题就是用反射。这也不例外,这里java提供的反射机制可以在运行时产生代理类,即动态代理。这篇博客已经太长了,分开来吧。先把动态代理的代码贴上。其中实际类和接口没有变化!

代理类工厂

import java.lang.reflect.Proxy;
//代理工厂类
public class ProxyFactory {
	//实际类
     private Object target;
     public ProxyFactory(Object target){
    	 this.target=target;
     }
     //根据传入的实际类生成代理
     public Object getInstance(){
    	 //实例化一个继承了InvocationHandler接口的预处理对象
    	 ProxyHandler handler=new ProxyHandler(target);
    	//反射得到代理类
    	 return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                 target.getClass().getInterfaces(),
                 handler);//handler即集中处理在动态代理类对象上的方法调用
     }
}

继承了InvocationHandler接口的handler类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class ProxyHandler implements InvocationHandler {
	private Object target;
	public ProxyHandler(Object target){
		this.target=target;
		}
	//所有代理方法的公共处理方法
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object result =null;
		result=method.invoke(target, args);
		//要买的东西断货时
		if(result.toString().equals("false")){
			System.out.println("给小孙打电话");
			return result;
		}else{
		return result;
		}
	}
}
public class Client {
   public static void main(String[] args){
	   //真正得到的代理类在客户端强转
	   DormitoryMember dormitoryMember=(DormitoryMember)new ProxyFactory(new DormitoryMemberImpl()).getInstance();
	   dormitoryMember.buyStapleFood("米饭");
   }
}

总结:动态代理通过反射把代理类和实际类之间的耦合解开了,同时通过继承了InvocationHandler接口的handler类对代理的方法进行统一的处理。也就解决静态代理所遇到的问题。

代理模式深入(一)——静态到动态

时间: 2024-10-04 12:16:33

代理模式深入(一)——静态到动态的相关文章

系统架构设计——设计模式之代理模式(二)CGLIB动态代理实现

像上一篇所说的代理模式其实是静态代理,在实际开发中其实应用不大,因为他需要事先知道被代理对象是谁,而且被代理对象和代理对象实现了公共的接口.实际情况往往并不能满足这些条件,我们往往在写代理模式的时候并不知道到时候被代理的对象是谁.解决办法就是--动态代理.以下我们将使用CGLIB实现动态代理. 一.动态代理概述 程序在运行期而不是编译器,生成被代理对象的代理对象,并且被代理对象并不需要和代理对象实现共同的接口.基于此,我们可以利用代理对象,提供一种以控制对被代理对象的访问. 1.1 动态代理的原

java 代理模式一: 静态代理

代理模式: 代理模式的作用:为其他对象提供一种代理以控制对 特定对象  的访问. 某种情况下,一个客户不想或者直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用:通过代理对象引用. 代理模式一般涉及到的角色: 抽象角色:声明真实对象和代理对象的共同接口.可以是一个抽象类或者一个接口. 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便任何时候都能代替真实对象. 同时,代理对象可以在执行真实对象操作时,附加其他的操作,

浅谈代理 模式与java中的动态代理

代理模式的定义: 代理模式是一个使用律非常高的模式,定义如下: 为其他对象提供一种代理,以控制对这个对象的访问. 类图: 简单的静态代理: public interface IRunner{ //这是一个代理类和被代理类都需要实现的接口 //在接口中定义一个抽象函数 public void request(); } //下面是真实的被代理类 public class Runner implements IRunner{ //实现接口中的方法 public void request(){ //实现

模式的秘密-代理模式(2)-JDK动态代理

代理模式-动态代理 (1) (2) 代码实践动态代理: 第一步:被代理类的接口: package com.JdkProxy; public interface Moveable { void move(); } 第二步:被代理类: package com.JdkProxy; import java.util.Random; public class Car implements Moveable { @Override public void move() { //实现开车 try { Thre

Spring学习五、Java配置Spring与代理模式

九.使用Java的方式配置Spring JavaConfig是Spring的一个子项目,在Spring4之后,成为了核心功能 @Configuration public class MyConfig { @Bean public User getUser() { return new User(); } } 纯Java配置,在SpringBoot中随处可见 十.代理模式 代理模式是SpringAOP的底层! 代理模式的分类 静态分类 动态代理 10.1 静态代理 角色分析: 抽象角色:一般会使用

代理模式(静态、动态)

代理模式的使用价值还是挺高的,各种框架中都用到了.把基础认真看看,学框架的时候也容易了. 关于静态代理: 代理模式的应用场景: 如果已有的方法在使用的时候需要对原有的方法进行改进,此时有两种办法: 1.修改原有的方法来适应.这样违反了“对扩展开放,对修改关闭”的原则. 2.就是采用一个代理类调用原有的方法,且对产生的结果进行控制.这种方法就是代理模式. 使用代理模式,可以将功能划分的更加清晰,有助于后期维护! 代理模式的要点: 1.“增加一层间接层”是软件系统中对许多负责问题的一种常见解决方法.

设计模式之--静态代理及动态代理模式

原文链接:http://www.studyshare.cn/blog/details/1181/0 一.概念 代理模式:为其他对象提供一种代理类用以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用 另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用,代理模式属于23中设计模式中的结构型设计模式. 代理模式可分为静态代理和动态代理. 代理结构如下图: 例如:客户(客户类)—>代购(代理类)—>海外下单(海外订单类),普通客户无法直接去海外下单,则向代购公司 下单,代

代理模式_静态代理

一.代理模式_静态代理 来到北京.首先第一件事就是租房子.然而北京租房子80%的都要通过中介,中介获得房屋出租的权限,出租房屋给房客.我们以这个很现实很亲近我们生活的例子来认识代理模式中的静态代理. 二.代理模式中的角色划分 2.1抽象角色:把真实角色和代理角色所共有的行为抽成一个接口或者抽象类. 2.2真实角色:被代理角色所代理的角色. 2.3代理角色:代理真实角色做某些工作. 三.静态代理示例 3.1抽象角色(把真实角色房东和代理角色中介所共有的行为出租房屋抽象成一个接口) package

谈谈Java的代理模式及动态代理

Java的动态代理在实践中有着广泛的使用场景,比如最场景的Spring AOP.Java注解的获取.日志.用户鉴权等.本篇文章带大家了解一下代理模式.静态代理以及基于JDK原生动态代理. 代理模式无论学习静态代理或动态代理,我们都要先了解一下代理模式. 先看百度百科的定义: 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 直接看定义可能有些难以理解,我们就以生活中具体的实例

java代理模式之静态代理

作为一个初级开发者,可能不会接触到代理模式,但是在很多框架的使用中都不知不觉使用了代理模式,比如servlet的过滤器链,spring的AOP,以及spring mvc的拦截器等.所以了解代理模式对于个人的成长是不可避免的. 在某些情况下,一个客户不想或者不能直接引用一个对象,此时可以通过一个称之为"代理"的第三者来实现间接引用.代理对象可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务. 原文和作者一起讨论:http: