java方法增强的三种方式:继承,装饰和代理

在java中,在不改变源代码的情况下,实现方法增强的方式有三种:

  • 1,继承
  • 2,装饰者模式
  • 3,代理模式(静态代理和动态代理)
1,继承模式:
  • 简单来说,就是通过继承的方式,在子类方法中添加相应的增强方法,然后通过调用子类方法来实现增强。
//继承比较简单,直接继承,重写中调用父类方法即可
2,装饰者模式:
  • 装饰者模式是真正完全不改变源码的情况下增强方法的一种方式,即便是调用方式也无需改变
  • 这里用自定义的连接池来进行说明
  • 在自定义连接池中,如果没有增强过Connection的话,那么是不能按照原来的方式直接调用connection.close();方法的,那么可以通过装饰,把连接池中的Connection对象直接在放入池之前包装成我自定义的Connection,这样从连接池中取出来的连接也是我自定义的连接,那么只需要在自定义的方法中实现close()和prepareStatement等就可以达到直接调用关闭方法的目的,具体如下:
//1,自定义连接池
/*
 * 对JDBC连接的封装,也就是自定义连接池
 * 其他一些方法也需要重写,但是不需要任何改变,所以这里就没有贴出来
 */
public class JDBCDatasource implements DataSource {
    private static LinkedList connections = new LinkedList();
    //往连接池中添加连接
    static{
        for(int i=0;i<5;i++){
            Connection connection = JDBCUtil.getConnection();
            JDBCConnection theConnection = new JDBCConnection(connections, connection);
            connections.add(theConnection);
        }
    }
    //重写这一个方法,如果没有增强过connection的话,需要调用这个方法归还连接到连接池中
    @Override
    public Connection getConnection() throws SQLException {
        if (connections.size() == 0) {
            for(int i=0;i<5;i++){
                Connection connection = JDBCUtil.getConnection();
                JDBCConnection theConnection = new JDBCConnection(connections, connection);
                connections.add(theConnection);
            }
        }
        return connections.removeFirst();
    }
     //新增一个方法
    public void returnConnection(Connection connection){
        connections.add(connection);
    }
}

//2,自定义连接类,实现相应的方法,并在自定义的连接池中进行包装,具体看1中的代码
//其他一些不需要修改的覆盖方法这里不再贴出
public class JDBCConnection implements Connection {
    private Connection connection;
    private LinkedList connections;
    public JDBCConnection(List connections, Connection connection) {
        this.connections = (LinkedList) connections;
        this.connection = connection;
    }
    //如果想要在关闭的时候添加到连接池,那么需要把连接池传进来,传进来最好的时候就是创建的时候
    @Override
    public void close() throws SQLException {
        System.out.println("here here!");
        connections.add(connection);
    }
    @Override
    public PreparedStatement prepareStatement(String sql) throws SQLException {
        return connection.prepareStatement(sql);
    }
}

//测试
JDBCDatasource datasource = new JDBCDatasource();
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
    connection = datasource.getConnection();
    preparedStatement = connection.prepareStatement("select * from product;");
    resultSet = preparedStatement.executeQuery();
    while(resultSet.next()){
        System.out.println(resultSet.getString("pname"));
    }
} catch (SQLException e) {
    e.printStackTrace();
} finally {
    //这行代码中封装了connection.close()方法
    JDBCUtil.closeAll(connection, preparedStatement, resultSet);
}

3,代理模式:
  • 代理分为动态代理和静态代理,区别就是静态代理是自己创建一个代理类,实现相应的被代理对象的方法,增加相应的增强代码。而动态代理是通过类加载器,反射等在运行时创建代理类,也就是不需要手动创建代理类,在对应的代理方法newProxyInstance中的代码块中直接添加增强代码;
  • 动态代理是在静态代理的基础上的拓展,所以先看下静态代理:
//1,首先需要有一个接口类,方便目标对象和代理对象去实现
public interface DogInterface {
    public void eat();
    public void run();
}

//2,目标对象中实现借口类
public class Dog implements DogInterface {
    @Override
    public void eat() {
        System.out.println("Dog  -----eat");
    }
    @Override
    public void run() {
        System.out.println("dog----run----");
    }
}

//3,创建一个代理对象,在代理对象中实现借口类,并在对应的方法中调用目标对象的方法。
public class DogProxy implements DogInterface {
    @Override
    public void eat() {
        System.out.println("dog在eat前,准备工作代码等");
                //这里调用目标对象的方法
        Dog dog = new Dog();
        dog.eat();
        System.out.println("dog在eat后收尾工作代码等");
    }
    @Override
    public void run() {
    }
}

//4,实际使用时候使用代理对象即可
public void proxyTest(){
    DogProxy proxy = new DogProxy();
    proxy.eat();//这里就ok了
}
  • 下面是动态代理的代码实现,前两步是完全一致的
    有一点需要注意的是:动态代理方法虽然能增强方法,但主要的使用场合是在拦截中进行相应的处理,如在全局的拦截器中进行乱码处理等
//1,首先需要有一个接口类,方便目标对象和代理对象去实现
public interface DogInterface {
    public void eat();
    public void run();
}

//2,目标对象中实现借口类
public class Dog implements DogInterface {
    @Override
    public void eat() {
        System.out.println("Dog  -----eat");
    }
    @Override
    public void run() {
        System.out.println("dog----run----");
    }
}

//3,在调用的时候使用代理类调用静态方法创建动态代理
 public void dynamicProxyTest(){
    DogInterface proxy = (DogInterface) Proxy.newProxyInstance(
            Dog.class.getClassLoader(), 
            Dog.class.getInterfaces(), //new Class[]{DogInterface.class}
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("before");
                    method.invoke(new Dog(), args);
                    System.out.println("after");
                return null;
        }
    });
    proxy.eat();
    proxy.run();
}
//搞定!

你可能感兴趣的