从课堂外取代吸气剂

时间:2018-12-01 19:11:24

标签: java

因此,假设我有一个名为Users的类,该类具有一个名为name的私有变量和一个只返回name变量的公共getter方法,那么我该如何做,以便该getter为所有的实例返回name +“ test”而不是访问用户类?

1 个答案:

答案 0 :(得分:4)

在Java中有几种方法可以做到这一点……

子类

首先,您可以扩展Users类并重写getter方法,如下所示:

public class TestUser extends User {
  @Override
  public String getName() { return super.getName() + "test"; }
}

然后,您可以通过User类引用TestUser实例,并调用getName方法以使用新行为:

User tu = new TestUser("username"); tu.getName(); // should return "usernametest"

动态代理

现在...如果由于某种原因无法扩展您的班级并且无法接触现有的User类,那么另一种方法是使用proxy via reflection

例如,如果您的User类实现了一个称为IUser(或其他任何东西)的接口,该接口声明了String getName()方法>

public interface IUser {
    String getName();
}

然后使用动态代理可以创建一个实现InvocationHandler的IUser代理,该代理将拦截getName方法并更改其返回值。

public class DebugProxy implements java.lang.reflect.InvocationHandler {
    private Object obj;

    public static Object newInstance(Object obj) {
        return java.lang.reflect.Proxy.newProxyInstance(
                obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(),
                new DebugProxy(obj));
    }

    private DebugProxy(Object obj) {
        this.obj = obj;
    }

    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        Object result;
        try {
            result = m.invoke(obj, args);
            if ("getName".equals(m.getName())) {
                return result + "test";
            }
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (Exception e) {
            throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
        }
        return result;
    }
}

然后您可以申请:

public class MainApp {
    public static void main(String[] args) {
        IUser userProxy = (IUser) DebugProxy.newInstance(new User("foo"));
        System.out.println(userProxy.getName());
    }
}

System.out.println将打印“最底”

这是一个丑陋的解决方案,仅在您的User类实现公开getName方法的接口时才有效。唯一的好处是您不需要继承也不需要更改User类代码:

我会说继承是必经之路。

希望这会有所帮助,并欢迎堆栈溢出!