0

我有一个由带有 getter/setter 方法的接口组成的对象模型。这些对象的实现是使用动态代理创建的,其中隐含字段的值(使用 JavaBean 命名约定)存储在 Map 中。

我想向这些接口添加方法以提供业务逻辑(你知道,就像一个真实的对象模型,而不仅仅是 POJO 的集合)。

我的第一个想法是创建实现每个接口但只提供业务方法实现的抽象类。然后,我将这些实现与 InvocationHandler 中的 Map 一起使用,以提供接口的完整实现。

就像是:

interface ModelObject extends BaseModel {
    void setFoo(String foo);
    String getFoo();

    void doSomething();
}

public abstract class ModelObjectImpl implements ModelObject {

    @Override
    public void doSomething()
    {
        // Do something
    }
}

public class ModelObjectInvocationHander implements InvocationHandler {

    Map<String, Object> fieldValues; // holds values for implied fields for getter setter
    ModelObject modelObject;         // holds reference to object implementing business methods

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        // Get implied field name for method name by removing "get"/"set" and lower casing next letter
        String fieldName = getBeanNameForMethod(method.getName());

        if (fieldValues.containsKey(fieldName)) {
            return fieldValues.get(fieldName);
        }

        // Not a getter/setter so must be a business method.  Delegate to implementation class
        return method.invoke(modelObject, args);
    }
}

除了我不能创建抽象类的实例之外,这样的东西(但显然更复杂)会起作用。我可以使 BusinessObjectImpl 非抽象并添加永远不会调用的 getter/setter 方法的无操作实现,但这只会使代码变得丑陋并导致维护问题。我也可以让 BusinessObjectImpl 实际上不实现 BusinessObject 接口,但这会破坏实现和接口之间的良好绑定,从而在接口和“实现”不同步时导致错误。

有没有什么鬼鬼祟祟的 Java 反射技巧可以用来调用这些业务方法?

更新:结合已经到位的 Java 动态代理框架和Javassist来为抽象实现类创建代理。这允许在根据需要添加业务方法之前对现有模型接口完全没有任何更改。现在已经具备向对象添加行为的能力。现在由开发人员开始编写真正的面向对象代码。

public class ModelObjectInvocationHandler implements InvocationHandler
{

    public ModelObjectInvocationHandler(Class<ModelImplementation<? extends BaseModel>> implementationClass)
    {
        if (implementationClass != null) 
        {
            ProxyFactory factory = new ProxyFactory();
            factory.setSuperclass(implementationClass);
            try
            {
                modelObject = (ModelObject) factory.create(new Class<?>[0], new Object[0]);
            }
            catch (Exception e)
            {
                // Exception handling
            }
        }
    }

    Map<String, Object> fieldValues; // holds values for implied fields for getter setter
    ModelObject modelObject;         // holds reference to object implementing business methods

    @Override 
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
    {

        // Get implied field name for method name by removing "get"/"set" and lower casing next letter
        String fieldName = getBeanNameForMethod(method.getName());

        if (fieldValues.containsKey(fieldName))
        {
            return fieldValues.get(fieldName);
        }

        // Not a getter/setter so must be a business method.  Delegate to implementation class
        if (modelObject != null)
        { 
            return method.invoke(modelObject, args);
        }

        return null;
    }
}

在运行时,我会扫描实现类并创建一个Map<Class<? extends BaseModel>, Class<ModelImplementation>>. 在为接口创建动态代理时,我在映射中找到它的实现类并将其传递给InvocationHandler. 任何与 bean 名称不匹配的方法都将委托给实现类的代理。当然,它比这要复杂一些,因为我必须考虑模型接口中的类层次结构和多重继承,但理论是合理的。

4

2 回答 2

0

一种方法是在新接口中定义所有“附加”或“业务”方法的合同,例如:

interface ModelObjectExtension {
    void doSomething();
}

interface ModelObject extends ModelObjectExtension {
    void setFoo(String foo);
    String getFoo();
}

public abstract class ModelObjectExtensionImpl implements ModelObjectExtension {

    @Override
    public void doSomething()
    {
        // Do something
    }
}

public class ModelObjectImpl extends ModelObjectExtension { 
    // whatever your current implementation is...
}

最后,您可以在处理程序中使用以下内容来调用扩展方法:

((ModelObjectExtension) modelObject).doSomething();
于 2013-07-13T23:17:56.793 回答
0

我不知道有任何标准的 Java 反射技巧可以做到这一点。cglib您可以使用或javaassist在类加载时动态扩展抽象类。这会稍微提高性能,因为不再Proxy需要对象。相反,您可以在创建新类时直接实现 getter/setter 方法。

没有这些技巧的第三种方法是使用委托模式:

public class ModelObjectImpl implements ModelObject {
  private final ModelObject delegate;

  public ModelObjectImpl(ModelObject delegate) { 
    this.delegate = delegate;
  }

  @Override
  public void doSomething() { /* Do something */ }

  @Override
  public String getFoo() { return delegate.getFoo(); }

  @Override
  public void setFoo(String foo) { delegate.setFoo(foo); }
}

将实现接口的 getter/setter 方法的代理提供给构造函数delegate参数。然而,虽然这看起来比存根方法(至少对我来说)更好,但它仍然是重复的代码。因此,如果您真的想要拥有这样的动态类,请使用动态字节码生成。

参考:

于 2013-07-13T22:56:05.530 回答