java的代理模式

  昨天做了一天的代理模式,现在总结一下,呵呵!总结得有点乱。。。

代理(Porxy)模式是一种常用的设计模式.
代理模式最主要的目的,原有的类对象由于某种原因不能访问,需要通过一个新的类来间接地去实现,这个新的类就称为代理类.
代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。
代理就是一个人或一个机构代表另一个人或者一个机构采取行动。某些情况下,客户不想或者不能够直接引用一个对象,
代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题对象与真实主题对象。
代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,
被代理对象必须有系统的其他角色代为创建并传入。

J2EE里的代理模式通常采用更强大的对象类替换目标对象.
以便在目标对象的方法前后执行我们希望执行的代码
例如,对于普通的业务逻辑组件,其方法应该有事务性,但这种开始事务和结束事务都是通用步骤,
因此原始业务逻辑对象的方法无须事务操作,而是由系统生成动态代理来负责事务操作,并调用实际的目标方法

 

1.静态代理(自定义代理类):
  
   【第1步】定义接口
  
    public interface Service
    {
        public void method1();
        public void method2();
    }

   ============================================================

   【第2步】实现接口

    public class ServiceImpl implements Service
    {
        public void method1()
        {
            System.out.println("执行业务方法1");
        }
        public void method2()
        {
            System.out.println("执行业务方法2");
        }
    }  

   ============================================================

   【第3步】实现代理类★★

    public class Supply implements Service{

 private Service im;
 
 public Supply(Service im)//★★构造方法,参数是目标对象
 {
     this.im=im;
 }

 public void method1()
        {
            System.out.println("给method1方法添加代理逻辑...  ... ...");//★★此处将公用的代码实现
            im.method1();
            ... ...
        }
        public void method2()
        {
            System.out.println("给method2方法添加代理逻辑...  ... ...");
            im.method2();
            ... ...
        }

    }

   ============================================================

   【第4步】运用代理
  
    public class test {

 public  static void main(String []s)
 {
  Service target=new ServiceImpl();//创建目标类
  Service proxy=new Supply(target);//创建代理类,将目标类作为参数进行传递
  
                proxy.method1();
                proxy.method2();//通过代理类来调用方法
 }
 
    }  


   说明:
     Spring的AOP底层就是用代理实现的。通过代理,可将公用的功能 "植入"方法中,
     现看第四步的主方法,首先创建目标类对象,也就是要被 "植入"公用功能的类对象。
     再创建代理类对象,在代理类中分别将方法重写了,在重写的过程中将公用功能"植入"到程序中。
     最后通过代理类调用方法就行了。

举个例子说明,老王买/卖鱼的例子
public class SellFisher{   
   public int sellFish(){
        System.out.println("my fish is delicious!!");
        return 10;
    }
}

 

这是一个具体的卖鱼类,表示鱼10元/斤,如果这个类被用到系统中的时候,系统应对变化的灵活性就会大打折扣,请看如下:
public class SellFishSystem{
    private SellFisher sellfish=new SellFisher();
                     //...
    public void sellFish(){
        sellfish.sellFish();
    }
}


如果以后鱼的价格变化,或者具体的卖鱼方法发生变化,就必须修改已经有的SellFisher的sellFish()的代码,这个情况
使得系统的可扩展性降低,我们肯定会想到解决方案了,定义一个接口,请看代码:
interface SellFisher{
    int sellFish();
}

public class SellFishSystem {
    private SellFisher sellfish;
    public void sellFish(){
        sellfish.sellFish();
    }
}


如果要卖鱼,可以新增加一个子类,新增加一个类的代码风险要大大低于对已有类的代码的修改.

接上面的例子来解释Proxy的模式就简单多了,比如现在鱼的价格变化,卖鱼的提示也发生变化了,我们需要一个新的Proxy类来实现
interface SellFisher {
    int sellFish();
}

public class ConcreteSellFisher implements SellFisher {
    public int sellFish() {
         System.out.println("my fish is delicious!!");
         return 10;
    }
}

public class ProxySellFisher implements SellFisher //运用代理{
    private SellFisher sell;
    public ProxySellFisher(SellFisher sell) {
        this.sell = sell;
    }
    public int sellFish() {
        System.out.println("the fish price higher");
        //编写公用的功能
        return sell.sellFish()+10;
    }
}

public class ClientTest {
    public static void main(String args[]) {
        SellFisher s = new ConcreteSellFisher();
        ProxySellFisher ps=new ProxySellFisher(s);
        ps.sellfish();
    }
}

 

 

看上面,这个是Proxy模式的代码例子实现,我们现在在SellFishSystem 使用ProxySellFisher来卖鱼了,
由ProxySellFisher再调用原来的ConcreteSellFisher类.具体的一些特征总结为:
1.有个代理类Proxy(和原来的实现类继承同一接口),该类里引用了原来的具体功能实现类(这里是ConcreteSellFisher)
2.重写实现方法,加一些新的变化的元素(比如鱼的价格上涨)

代理模式另一个例子.我们要卖房子,可以有多种方法,通过中介公司卖,中介公司要收一定的手续费.中介公司就相当于代理.

 

========================================================================================

 


2.动态代理(自定义代理类):

   JDK里的Proxy类也实现了这个模式,只不过它叫动态代理,因为它的代理类变成了InvocationHandler了,执行的方法是invoke了,
   从而变得更加灵活了(第一步与第二步都一样)

  
   【第1步】定义接口
  
    public interface Service
    {
        public void method1();
        public void method2();
    }

   ============================================================

   【第2步】实现接口

    public class ServiceImpl implements Service
    {
        public void method1()
        {
            System.out.println("执行业务方法1");
        }
        public void method2()
        {
            System.out.println("执行业务方法2");
        }
    }  

   ============================================================

   【第3步】实现代理类★★ 
   
    import java.lang.reflect.*;//★★导包
    import java.util.*;

    public class ProxyHandler implements InvocationHandler//★★实现InvocationHandler接口
    {
       private Object target;//★★定义目标类(这里用的是Object类去引用)

       public void setTarget(Object o)
       {
           this.target = o;
       }

       public Object invoke(Object proxy, Method method, Object[] args)throws Exception//★★实现接口中的方法
                           //第二个参数是方法的名称,可以通过method.getName()获取方法名
                           //第三个参数是方法中的参数,是一个数组
       {
          Object result = null;
          if (method.getName().equals("method1"))//判断方法名是否是 "method1"
          {
              System.out.println("======开始事务=======");
              result =method.invoke(target, args);//★★★★调用目标对象中的方法,第一个参数是目标类实例对象,第二参数是方法中的参数
              System.out.println("======提交事务=======");
          }
          else
          {
              result =method.invoke(target, args);
          }
          return result;
       }
      
    }

   ============================================================

   【第4步】将接口与代理类相关联★★ 

    import java.lang.reflect.*;

    public class MyProxyFactory
    {
        public static Object getProxy(Object object)//定义方法,参数是目标对象
        {
           ProxyHandler handler = new ProxyHandler();//创建代理类对象
           handler.setTarget(object);设置托管对象的目标对象
       
          
           return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),handler);★★★★
                  //通过Proxy类的静态方法进行动态代理,返回代理后的类对象,但是Object类型
                  //第一个参数是用来创建 动态代理 的ClassLoader对。
                  //第二个参数是目标对象的接口
                  //第三个参数是代理类的实体类
        }
    }

   ============================================================

   【第5步】运用代理

    public class TestService
    {
        public static void main(String[] args)
        {
           Service service = null;

           Service targetObject = new ServiceImpl();//创建目标类对象
           Object proxy = MyProxyFactory.getProxy(targetObject);//通过动态代理类获取
           if (proxy instanceof Service)//判断返回的对象是否是接口的实例对象
           {
              service = (Service)proxy;//强转
           }
           service.method1();//调用代理后的方法
           service.method2();
        }
    }

 

j2ee在1.3以后提供了Proxy、InvocationHandler来支持代理模式。对于java内建的代理来说,就是client不直接访问对象,
而是通过Proxy对象来访问,而在访问实际对象前后我们可以自己定义一些其他的操作。具体来讲,
client访问的对象通过Proxy.newProxyInstance()给出,client要访问的实际的类可以通过Proxy.getProxyClass获得,
而实际的调用将访问到我们实现的 InvocationHandler对象的invoke()方法中来。
在invoke()方法中我们可以为实际的调用添加额外的代码以满足不同的需要。

 

    现在还是用买鱼的例子:
  
import java.lang.reflect.*;
import java.util.*;

interface SellFisher {
    int sellFish();
}

 class ConcreteSellFisher implements SellFisher {

    public int sellFish() {
         System.out.println("my fish is delicious!!");
         return 10;
    }

}
 class ProxySellFisher implements InvocationHandler {

    private SellFisher sell;
    public ProxySellFisher(SellFisher sell) {
        this.sell = sell;
    }
    public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
        System.out.println("请登记");
        return (Integer)method.invoke(sell, args);
  }
}
 class ClientTest {
    public static void main(String args[]) {
        SellFisher s = new ConcreteSellFisher();
        InvocationHandler p = new ProxySellFisher(s);
        Object obj = Proxy.newProxyInstance(s.getClass().getClassLoader(), s.getClass().getInterfaces(), p);
        ((SellFisher)obj).sellFish();
    }
}
  

    请注意,invoke(Object obj,Method method,Object[] args),这里的第一个参数obj其实可以看作没有用处的,
    不知道jdk为什么要把它也当作一个参数放这里,methd.invoke()方法,需要把原来的具体实现类(目标类)作为参数传递进去,
    method.invoke(obj,args)相当于obj.method(args)


    总结,从设计模式的角度讲,大家以后编程中,尽量要面向接口,更通俗一点就是,一个类中使用的别的对象成员变量,
    最好定义成接口的变量而不是实际实现类的变量
    代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,
    一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值