十二、结构型模式——代理模式

一、代理模式简介
中国人是一个含蓄的民族,讲求微妙和间接的交流方式。对象间的间接通信也同样是面向对象的设计中一条重要的"审美观"。间接的通信可以给出较低的耦合关系,较强的合作关系,以及微妙的结构和易于复用的设计架构。
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是: 可以在不 改目标对象的基础上,增强额外的功能操作,即扩展目标对象的功能 .(通过反射完成)
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。

1.常见的代理
1.远程代理(Remote Proxy):对一个位于不同的地址空间对象提供一个局域代表对象,如RMI中的stub
2.虚拟代理(Virtual Proxy):根据需要将一个资源消耗很大或者比较复杂的对象,延迟加 载,在真正需要的时候才创建,节省资源。
3.保护代理(Protect or Access Proxy):控制对一个对象的访问权限。
4.智能引用(Smart Reference Proxy):提供比目标对象额外的服务和功能。


2.例子分析
客户真正想访问的是目标对象,当客户类真正可以访问的是代理对象,客户类对目标类的访问是通过访问代理对象来实现的,代理类,目标类实现了同一个接口
比如代理律师(动态代理,有了官司才请律师)
(1)当事人和律师都为同一件事而努力
(2)法院所有事务是通过律师完成的
(3)法院需要当事人做什么事的时候,代理律师会通知当事人,为其出出谋划策,即增强当事人(当事人不需要了解法律,通过代理律师为其增强法律知识)

法律顾问(静态代理,一直聘请这个人)

二、静态代理

十二、结构型模式——代理模式_第1张图片

程序运行之前,代理类和目标类就确定了关系,代理类的.class文件就已经存在
1.代码实现

十二、结构型模式——代理模式_第2张图片

追美女的一种方式是从她的朋友下手,让她的死党帮忙,那就离成功没有多远了。好,我们把她的死党作为这个美女的代理,开始的时候我们当然要和代理打交道了,我们用代理模式实现以下。定义一个接口,这个接口有一个behavior()方法。

public interface Girl {     
    public void behavior();  
 }    

//然后让美女类实现这个接口
public class NiceGirl implements Girl {    
   private String name;     
   public NiceGirl(String name){   
    	  this.name = name;     
    }     
  @Override    
   public void behavior() {     
      System.out.println(this.name+"长的非常nice");     
      System.out.println(this.name+"说话也非常nice");     
      }         
 }    
接下来定义代理类,代理类也实现了Girl接口,不但如此,代理类还要关联它要代理的对象,所以要定义Girl类型的一个成员变量。
   public class GirlAgent implements Girl {            
      private Girl girl;        
      public GirlAgent(Girl girl) {     
        super();     
       this.girl = girl;     
      }       
       @Override    
      public void behavior() {     //增强方法
        Random rand = new Random();     
        if(rand.nextBoolean())     
         {     
        System.out.println("我安排你们上自习");     
            girl.behavior();     
        }     
       else{     
          System.out.println("先看你的表现,上自习以后再说");     
       }     
    }     
下面编写一个测试类
public   class  Client {       
   public   static   void  main(String[] args) {               
    Girl niceGirl =  new  NiceGirl( "小美" );     
     Girl friend =  new  GirlAgent(niceGirl);     
        friend.behavior();      
  }          
}    
那装饰模式是怎么回事呢?装饰模式只要改动一处代码就可以了,对代理类的behavior()方法改动如下。
public   void  behavior() {       
System.out.println( "我家MM不但知书达礼,而且还会做饭" );     
girl.behavior();     
        }   
2.代理模式和装饰者模式的不同
两者其它部分相同,只是 代理模式中,代理类对被代理的对象 控制权 ,决定其执行或者不执行。而装饰模式中,装饰类对代理对象 没有控制权 ,只能为其增加一层装饰,以加强被装饰对象的功能,仅此而已。
什么情况下用代理模式什么情况下用装饰模式呢?
如果是为了给对象增加功能,那就用装饰模式。比如一个Plane类它的fly()方法中飞行速度是300m/s,那能不能实现500m/s的飞机对象呢?有装饰模式就可以实现。700m/s的呢?装饰两次就行了。不是定义两个装饰器类,而是定义一个装饰器能够增速200m/s,然后装饰两次。
 

三、动态代理 (目标对象实现了接口,重写其中方法,)
代理的是接口,所以只能将代理对象转换为接口,不能转换为实现类
程序运行的时候,代理类和目标类才确定了关系
没有代理类,只有代理对象,代理对象是通过代理工具,代理工厂生成的
在目标类运行方法的时候才对方法进行了增强
JDK的动态代理
目标类
//目标类,代理类要增强的类
public class SomeServiceImpl implements ISomeService {
	@Override
	public String doFirst() {
		System.out.println("执行doFirst");
		return "aaa";		
	}

	@Override
	public void doSecond() {
		System.out.println("执行doSecond");		
	}
}
public class MyTest {	
	public static void main(String[] args) {	
		/*参数一loader:目标类的类加载器	
		 **参数二Interfaces:目标类所实现的所有接口		
		 * *参数三:匿名内部类,在内部增强方法 */		
		ISomeService target = new SomeServiceImpl();	
		//由Proxy类的newProxyInstance()生成一个动态代理对象	
		ISomeService service = (ISomeService) Proxy.newProxyInstance(	
				target.getClass().getClassLoader(), //得到类加载器		
				target.getClass().getInterfaces(),  //得到类实现的接口	
				new InvocationHandler() {			
					@Override					//proxy:代理对象			
					//method:增强方法,在调用方法的时候自动获得		
					//Object[] args:目标方法的参数列表,调用方法自动获得	
					//对方法进行了增强				
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {		
						Object result = method.invoke(target, args); //invoke表示执行方法	
						if(result!=null){ //对原方法的结果进行修饰,完成对原方法的加强		
						    result = ((String)result).toUpperCase();					
							}								return result;				
							//原方法的返回值不能为空				
						}			
					});		
						String result = service.doFirst();//这个方法返回值就是invoke方法返回值	
						System.out.println(result);	}}
					}
				}
			}
	}
}
2. 动态代理好处
1、减少编程的工作量:假如需要实现多种代理处理逻辑,只要写多个代理处理器就可以了,无需每种方式都写一个代理类。
2、系统扩展性和维护性增强,程序修改起来也方便多了(一般只要改代理处理器类就行了)。

四、CGLIB动态代理 (目标对象没有实现接口)
目标类
//目标类,没有实现任何接口
public class SomeService {
	public String doFirst(){
		System.out.println("正在执行doFirst方法");
		return "adad";	
	}
	public void doSecond(){
		System.out.println("正在执行doSecond方法");		
	}
}
代理工具
//原理,先决定目标类,再执行增强方法
public class CGLIBFactory implements MethodInterceptor {

	private SomeService target;
	private Enhancer enhancer = new Enhancer();
	public CGLIBFactory() {
		super();
	}

	public CGLIBFactory(SomeService target) {
		super();
		this.target = target;
	}

	public SomeService myCglibCreater(){		
		/*增强原理:子类增强了父类
		 * cglib创建的是目标类的子类对象
		 * 指定父类,即目标类
		 */
		enhancer.setSuperclass(SomeService.class);
		//设置回调接口对象(实现callback接口的对象)
		//MethodInterceptor继承了callback
		//当执行完目标类的方法的时候会自动调用接口方法
		enhancer.setCallback(this);
		//create()用于创建cglib动态代理对象
		return (SomeService) enhancer.create();	
	}
	
	//回调接口的方法
	@Override
	public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
		Object invoke = method.invoke(target, args);
		if(invoke !=null){
			invoke = ((String)invoke).toUpperCase();
		}		
		return invoke;		
	}	
}
静态代理和动态的区别,静态代理增强方法后调用的是代理类的方法,而动态代理调用的还是被代理类的方法(因为动态代理没有代理类)


你可能感兴趣的:(设计模式,代理模式,设计模式,动态代理,java)