关于java:设计模式之代理模式

4次阅读

共计 3712 个字符,预计需要花费 10 分钟才能阅读完成。

代理模式

结构型模式

在代理模式(Proxy Pattern)中,一个类代表另一个类的性能。

在代理模式中,咱们创立具备现有对象的对象,以便向外界提供性能接口。

介绍

用意: 为其余对象提供一种代理以管制对这个对象的拜访。

次要解决: 在间接拜访对象时带来的问题,比如说:要拜访的对象在近程的机器上。在面向对象零碎中,有些对象因为某些起因(比方对象创立开销很大,或者某些操作须要安全控制,或者须要过程外的拜访),间接拜访会给使用者或者系统结构带来很多麻烦,咱们能够在拜访此对象时加上一个对此对象的拜访层。

何时应用: 想在拜访一个类时做一些管制。

如何解决: 减少中间层。

要害代码: 实现与被代理类组合。

具体实现

第一种:动态代理

咱们将创立一个 ITeacherDao 接口和实现了 ITeacherDao 接口的实体类。TeacherDaoProxy 是一个代理类,减少一些额定的性能。

咱们的演示类应用 TeacherDaoProxy 来获取要加载的 ITeacherDao 对象,并依照需要进行显示。

第一步:创立一个接口

public interface ITeacherDao {void teach();

}

第二步:创立实现类

public class TeacherDao implements ITeacherDao {

    @Override
    public void teach() {System.out.println("老师授课中...");
    }
}

第三步:创立代理类

public class TeacherDaoProxy implements ITeacherDao {

    // 指标对象, 通过接口来聚合
    private ITeacherDao target;

    public TeacherDaoProxy(ITeacherDao target) {this.target = target;}

    @Override
    public void teach() {System.out.println("开始代理...");
        target.teach();
        System.out.println("完结代理...");
    }
}

第四步:创立测试类

public class Client {public static void main(String[] args) {// 创立指标对象 ( 被代理对象)
        TeacherDao teacherDao = new TeacherDao();
        // 创立代理对象, 同时将被代理对象传递给代理对象
        TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
        // 通过代理对象, 调用到被代理对象的办法
        teacherDaoProxy.teach();}
}

运行如下:

 开始代理...
老师授课中...
完结代理...

长处:

    在不批改指标对象的性能前提下,能通过代理对象来对指标性能进行扩大。

毛病:

    1、因为代理对象和指标对象都要实现同一接口,所以会有很多代理类。

    2、一旦接口减少办法,指标对象和代理对象都要保护。

    3、因为在客户端和指标对象之间减少了代理对象,因而有些类型的代理模式可能会造成申请的处理速度变慢。

第二种:动静代理(JDK 代理)

第一步:创立一个接口

public interface ITeacherDao {void teach();

}

第二步:创立实现类

public class TeacherDao implements ITeacherDao {

    @Override
    public void teach() {System.out.println("老师授课中...");
    }

}

第三步:创立动静代理类

public class ProxyFactory {

    // 保护指标对象
    private Object target;

    public ProxyFactory(Object target) {this.target = target;}

    // 给指标对象生成代理对象
    public Object getProxyInstance() {
        //1. ClassLoader loader : 指定以后指标对象应用的类加载器, 获取加载器的办法固定.
        //2. Class<?>[] interfaces : 指标对象实现的接口类型, 应用泛型办法确认类型.
        //3. InvocationHandler h : 事件处理, 执行指标对象的办法时, 会触发事件处理器的办法, 会把以后执行的指标对象办法作为参数传入.
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), (proxy, method, args) -> {System.out.println("动静代理开始...");
            Object returnVal = method.invoke(target, args);
            System.out.println("动静代理完结...");
            return returnVal;
        });
    }
}

第四步:创立测试类

public class Client {public static void main(String[] args) {// 创立指标对象 ( 被代理对象)
        ITeacherDao target = new TeacherDao();
        // 给指标对象生成代理对象
        ProxyFactory proxyFactory = new ProxyFactory(target);
        ITeacherDao proxyInstance = (ITeacherDao) proxyFactory.getProxyInstance();
        proxyInstance.teach();}
}

运行如下:

 动静代理开始...
老师授课中...
动静代理完结...

要害代码:

  • java.lang.reflect.Proxy: 生成动静代理类和对象;
  • java.lang.reflect.InvocationHandler(处理器接口):能够通过 invoke 办法实现

总结

尽管这个变体胜利的防止了动态代理中的反复缺点,然而它依然有一个局限性,它无奈应用不是从接口继承的实现类,就是说,应用动静代理类,原始类必须先要实现一个或多个接口,这个接口也就是代理接口。

第三种:Cglib 代理

在应用 Cglib 代理时候须要引入绝对应的 Jar 包,这里就不展现 maven 是如何配置的。

第一步:创立指标类

public class TeacherDao {public void teach(){System.out.println("老师授课中... 我是 cglib 代理的, 不须要实现接口");
    }

}

第二步:创立代理类

public class ProxyFactory implements MethodInterceptor {

    // 保护一个指标对象
    private Object target;

    public ProxyFactory(Object target) {this.target = target;}

    // 返回一个代理对象, 是 target 的指标对象
    public Object getProxyInstance() {
        //1. 创立一个工具类
        Enhancer enhancer = new Enhancer();
        //2. 设置父类
        enhancer.setSuperclass(target.getClass());
        //3. 设置回调函数
        enhancer.setCallback(this);
        //4. 创立子类对象, 及代理对象
        return enhancer.create();}

    // 重写 intercept 办法, 会调用指标对象的办法
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {System.out.println("cglib 代理模式开始...");
        Object returnVal = method.invoke(target, args);
        System.out.println("cglib 代理模式完结...");
        return returnVal;
    }
}

第三步:创立测试

public class Client {public static void main(String[] args) {
        // 指标对象
        TeacherDao target = new TeacherDao();
        // 给指标对象生成代理对象
        ProxyFactory proxyFactory = new ProxyFactory(target);
        TeacherDao proxyInstance = (TeacherDao) proxyFactory.getProxyInstance();
        proxyInstance.teach();}
}

运行如下:

cglib 代理模式开始...
老师授课中... 我是 cglib 代理的, 不须要实现接口
cglib 代理模式完结...

总结:

Cglib 原理是针对指标类生成一个子类,笼罩其中的所有办法, 所以指标类和办法不能申明为 final 类型和 static 类型!
从执行效率上看,Cglib 动静代理效率较高。

正文完
 0