2013-07-13 59 views
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方法的do-nothing實現,但這隻會使代碼變醜並導致維護問題。我也可以讓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名稱的方法都會委派給實現類的代理。當然,它比這更復雜一點,因爲我必須考慮模型接口中的類層次結構和多重繼承,但理論是正確的。

回答

0

我不知道任何標準的Java反射技巧會這樣做。您可以在類加載時使用cglibjavaassist動態擴展抽象類。這會稍微改善性能,因爲不再需要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說法。然而,雖然這看起來好於存根方法(至少對我來說)它仍然是重複的代碼。所以,如果你真的想擁有這樣的動態類,那就去動態字節碼生成吧。

參考文獻:

+0

同意。我正在使用基於[先前的問題/答案]的Javassist的解決方案(http://stackoverflow.com/questions/3291637/alternatives-to-java-lang-reflect-proxy-for-creating-proxies-of-抽象類) – DanN

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(); 
+0

有趣,但現在你需要在兩個地方查找業務對象的方法。另外,出於與上述相同的原因,您不能將ModelObjectExtensionImpl設置爲「abstract」。當然,在你的例子中實際上並不需要是抽象的。 – DanN

相關問題