首页 > 解决方案 > 从课堂外替换吸气剂

问题描述

所以,假设我有一个名为 Users 的类,它有一个名为 name 的私有变量和一个只返回 name 变量的公共 getter 方法,我怎样才能让 getter 为类的所有实例返回 name +“test”而不是可以访问用户类?

标签: java

解决方案


好吧,在 Java 中有几种方法可以做到这一点……</p>

子类

首先,您可以扩展您的 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 类,那么另一种方法是通过反射使用代理

例如,如果您的 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 将打印“footest”

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

我会说继承是要走的路。

希望这有助于并欢迎堆栈溢出!


推荐阅读