美文网首页Java学习笔记Java 杂谈
java方法增强的三种方式:继承,装饰和代理

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

作者: 张不二01 | 来源:发表于2017-07-15 17:58 被阅读120次

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

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

相关文章

  • Java 增强对象

    Java增强对象,无非是为了让该对象具有更多的功能。Java增强对象主要有三种方式:继承、装饰者模式和动态代理。 ...

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

    在java中,在不改变源代码的情况下,实现方法增强的方式有三种: 1,继承 2,装饰者模式 3,代理模式(静态代理...

  • 设计模式六(IO的不之情-装饰者模式)

    前言 java中对象的增强手段大致有三种,继承、装饰者模式、动态代理。先来看看三者的特点: 继承 被增强的对象是固...

  • Java 设计模式学习--装饰器模型

    其实无论是代理模式还是装饰模式,本质上就是对原有对象增强的方式~对象增强方式有下面几种方式 继 承 继承父类,子类...

  • 面试题:增强一个对象的方法的三种方式

    面试题:增强一个对象的方法的三种方式 1. 继承 使用这种方式必须满足的条件是:被增强的方法的所在类能被继承,并且...

  • java装饰者模式

    java中增强方法的功能有三种方式 1.通过继承,重写父类的方法,在调用super的基础上,再添加代码 2.动态代...

  • Java方法增强的三种方式,你知道吗?

    在实际开发中,我们往往需要对某些方法进行增强,常用的方法增强的方式有三种。 类继承 、方法覆盖——必须控制对象创建...

  • Java实现线程的三种方式和区别

    Java实现线程的三种方式和区别 Java实现线程的三种方式: 继承Thread 实现Runnable接口 实现C...

  • 动态代理

    动态代理,其实就是一种特殊的增强方法的方式,而增强原有方法不会跟他原先的类发生关系,即没有继承关系,也没有实现关系...

  • java 多线程创建及运行

    java多线程实现方式1.1 三种创建线程的方式 继承Thread类,重写run()方法 实现Runable()接...

网友评论

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

    本文链接:https://www.haomeiwen.com/subject/zxhzhxtx.html