代理模式

代理模式的用途

代理模式是对类的扩展
比如有一个字体提供类,有多种实现(从磁盘,从网络,从系统)

public interface FontProvider {
    Font getFont(String name);
}

public abstract class ProviderFactory {
    public static FontProvider getFontProvider() {
        return new FontProviderFromDisk();
    }
}

public class Main() {
    public static void main(String[] args) {
        FontProvider fontProvider = ProviderFactory.getFontProvider();
        Font font = fontProvider.getFont("微软雅黑");
        ......
    }
}
现在我们希望给他加上一个缓存功能,我们可以用静态代理来完成

public class CachedFontProvider implements FontProvider {
    private FontProvider fontProvider;
    private Map<String, Font> cached;

    public CachedFontProvider(FontProvider fontProvider) {
        this.fontProvider = fontProvider;
    }

    public Font getFont(String name) {
        Font font = cached.get(name);
        if (font == null) {
            font = fontProvider.getFont(name);
            cached.put(name, font);
        }
        return font;
    }
}


/* 对工厂类进行相应修改,代码使用处不必进行任何修改。
   这也是面向接口编程以及工厂模式的一个好处 */
public abstract class ProviderFactory {
    public static FontProvider getFontProvider() {
        return new CachedFontProvider(new FontProviderFromDisk());
    }
}

静态代理

代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问,因为在某些情形下,我们不能直接或不方便直接访问某些类,或者我们需要对访问的类做一些特殊的处理,这时便可以采用代理模式了。
代理模式分为动态代理和静态代理,其中静态代理比较简单,它要求代理类和被代理类必须事先已经存在,代理类的接口和所代理方法都已明确指定。如果需要为不同的真实主题类提供代理类或者代理一个真实主题类中的不同方法,都需要增加新的代理类,这将导致系统中的类个数急剧增加,因此需要想办法减少系统中类的个数。动态代理可以让系统能够根据实际需要来动态创建代理类,让同一个代理类能够代理多个不同的真实主题类而且可以代理不同的方法。

interface Subject  
{  
    public void fun();  
}  
class SubjectImpl implements Subject  
{  
    public void fun()  
    {  
        System.out.println("this is subject impl");  
    }  
}  
  
class Proxy implements Subject  
{  
    private Subject subject = null;//将需要被代理的类设置为类属性  
    public void fun()  
    {  
        before();//do something before..  
        if(subject == null)  
        {  
            subject = new SubjectImpl();//初始化  
            subject.fun();//实际调用的是被代理类中的fun方法  
        }  
        after();//do something after…  
    }  
    private void before()  
    {  
        System.out.println("before.......");  
    }  
    private void after()  
    {  
        System.out.println("after........");  
    }  
      
}  
class Main  
{  
    public static void main(String[] args)  
    {  
        Proxy proxy = new Proxy();  
        proxy.fun();  
    }  
}

动态代理

从JDK 1.3开始,Java语言提供了对动态代理的支持,Java语言实现动态代理时需要用到位于java.lang.reflect包中的一些类,现简要说明如下:
1.Proxy类
Proxy类提供了用于创建动态代理类和实例对象的方法,它是所创建的动态代理类的父类,它最常用的方法如下:
· public static Class<?> getProxyClass(ClassLoader loader,Class<?>… interfaces):该方法用于返回一个Class类型的代理类,在参数中需要提供类加载器并需要指定代理的接口数组(与真实主题类的接口列表一致)。
· public static Object newProxyInstance(ClassLoader loader, Class<?>[]interfaces, InvocationHandler h):该方法用于返回一个动态创建的代理类的实例,方法中第一个参数loader表示代理类的类加载器,第二个参数interfaces表示代理类所实现的接口列表(与真实主题类的接口列表一致),第三个参数h表示所指派的调用处理程序类。
2.InvocationHandler接口
InvocationHandler接口是代理处理程序类的实现接口,该接口作为代理实例的调用处理者的公共父类,每一个代理类的实例都可以提供一个相关的具体调用处理者(InvocationHandler接口的子类)。在该接口中声明了如下方法:
· public Object invoke(Objectproxy, Method method, Object[] args):该方法用于处理对代理类实例的方法调用并返回相应的结果,当一个代理实例中的业务方法被调用时将自动调用该方法。invoke()方法包含三个参数,其中第一个参数proxy表示代理类的实例,第二个参数method表示需要代理的方法,第三个参数args表示代理方法的参数数组。
动态代理类需要在运行时指定所代理真实主题类的接口,客户端在调用动态代理对象的方法时,调用请求会将请求自动转发给InvocationHandler对象的invoke()方法,由invoke()方法来实现对请求的统一处理。

 
	动态代理实质上是静态代理的升级版,在静态代理的基础上,代理类由代码生成,只用告诉其要代理的类实现的接口, 以及一个类  加载器去加载机器生成的字节码,最后再加上代理方法中要执行的操作(handler)
 


常规使用

class InvocationHandlerImpl implements InvocationHandler  
{  
    private Object target = null;  
    InvocationHandlerImpl(Object target)  
    {  
        this.target = target;  
    }  
    public Object invoke(Object proxy,Method method,Object[] args)throws Throwable  
    {  
        Object obj = null;  
        if(method.getName().equals("fun"))  
        {  
            System.out.println("before...");  
            obj = method.invoke(target,args);  
            System.out.println("after...");  
        }  
        else  
        {  
            obj = method.invoke(target,args);  
        }  
        return obj;  
          
          
    }  
}  
  
class Main//测试  
{  
    public static void main(String[] args)  
    {  
        SubjectImpl subimpl = new SubjectImpl();  
        InvocationHandlerImpl handler = new InvocationHandlerImpl(subimpl);  
          
          
        Subject sub = (Subject)Proxy.newProxyInstance(subimpl.getClass().getClassLoader(),  
                                subimpl.getClass().getInterfaces(),handler);  
        sub.fun();  
    }  
}

通过匿名内部类使用

class Main  
{  
    public static void main(String[] args)  
    {  
        final SubjectImpl sub = new SubjectImpl();  
        Subject su = (Subject)Proxy.newProxyInstance(sub.getClass().getClassLoader(),  
                        sub.getClass().getInterfaces(),new InvocationHandler()  
                        {  
                            public Object invoke(Object proxy,Method method,Object[] args)throws Throwable  
                            {  
                                Object obj = null;  
                                if(method.getName().equals("func"))  
                                {  
                                    System.out.println("before...");  
                                    obj = method.invoke(sub,args);  
                                    System.out.println("after...");  
                                }  
                                else  
                                {  
                                    obj = method.invoke(sub,args);  
                                }  
                                return obj;  
                            }  
                        }  
        );  
        su.fun();  
    }  
}

在InvocationHandler实现类内部创建一个bind方法,用来返回代理类实例:

class InvocationHandlerImpl implements InvocationHandler  
{  
    private Object target = null;  
    public Object bind(Object target)  
    {  
        this.target = target;  
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
                        target.getClass().getInterfaces(),this);  
    }  
    public Object invoke(Object proxy,  Method method,Object[] args) throws Throwable  
    {  
        Object obj = null;  
        if(method.getName().equals("fun"))  
        {  
            before();  
            obj = method.invoke(target,args);  
            after();  
        }  
        else  
        {  
            obj = method.invoke(target,args);  
        }  
        return obj;  
        //return null;  
    }  
    private void before()  
    {  
        System.out.println("before...");  
    }  
    private void after()  
    {  
        System.out.println("after...");  
    }  
}  
class Main  
{  
    public static void main(String[] args)  
    {  
        InvocationHandlerImpl proxy = new InvocationHandlerImpl();  
        Subject sub = (Subject)proxy.bind(new SubjectImpl());  
        sub.fun();  
    }  
}
原博客 点击这里






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值