2

タイトルは不安そうに見えるかもしれませんが、説明させてください。

私は興味深い課題に直面しています。そこでは、各属性に関連するメタデータ(UPDATEDやNO_UPDATEなどの編集フラグを持つint値の列挙型)を格納するオブジェクトを関連付けたクラスの階層があります。

2つのオブジェクトをマージするときに問題が発生します。これは、クラスのすべてのフィールドをチェックして、更新されているかどうかを確認し、変更をスキップまたは適用したくないためです。

私の考え:リフレクション。

すべてのオブジェクトはインターフェイスの背後にあるため、IObject.class.getMethods()を使用して、次のようにその配列を反復処理できます。

IClass class = //Instance of the first class;
IAnotherClass anotherClass = //Instance of the second class;
for(Method m  : IObject.class.getMethods()) {
    if(m.getName().startsWith("get")) {
        try {
            //Under this method (which is a getter) I cast it on 
            //both classes who implement interfaces that extend an
            //interface that defines the getters to make them
            //consistent and ensure I'll invoke the same methods.
            String propertyClass = (String)m.invoke(class);
            String propertyAnotherClass = (String)m.invoke(anotherClass);
            if(propertyClass != propertyAnotherClass) {
                //Update attribute and attribute status.
            }
        } catch (Exception e) {

        }
    }
}

これを実装する別の方法はありますか、それとも属性ごとに属性を呼び出してそのようなチェックを行う長いメソッドに固執する必要がありますか?オブジェクトはそれほど変更されることはなく、アーキテクチャは非常にモジュール化されているため、フィールドが変更されても更新はあまり必要ありませんが、そのようなメソッドを変更する必要があるので少し心配です。

編集1:私はこれまでに得たものの実用的なコードを投稿しています。このコードは私にとっては解決策ですが、うまく機能するので、時間を費やすためではなく、車輪を再発見したくないために、最後のリソースとして使用しています。これを使用する場合は、メソッドを使用して静的リストを作成するので、AlexRが指摘した事実を考慮して、そのリストを1回だけフェッチする必要があります。

private static void merge(IClazz from, IClazz to) {
        Method methods[] = from.getClass().getDeclaredMethods();
        for(Method m : methods) {
            if(m.getName().startsWith("get") && !m.getName().equals("getMetadata")) {
                try {                   
                    String commonMethodAnchor = m.getName().split("get")[1];
                    if(!m.getReturnType().cast(m.invoke(from)).equals(m.getReturnType().cast(m.invoke(to)))) {
                        String setterMethodName = "set" + commonMethodAnchor;
                        Method setter = IClazz.class.getDeclaredMethod(setterMethodName, m.getReturnType());
                        setter.invoke(to, m.getReturnType().cast(m.invoke(from)));
                        //Updating metadata
                        String metadataMethodName = "set" + commonMethodAnchor + "Status";
                        Method metadataUpdater = IClazzMetadata.class.getDeclaredMethod(metadataMethodName, int.class);
                        metadataUpdater.invoke(to.getMetadata(), 1);
                    }

                } catch (Exception e) {

                }
            }
        }
    }

MetadataUpdaterは、実際のシナリオで使用している「UPDATED」フラグをシミュレートするためだけに値を1に設定します。

編集3:あなたの提案と方向性をありがとうJuan、DavidとAlexR!彼らは本当に私が最初は考えていなかったことを考えるように私に指示しました(それらのすべてが私を助けたので私はあなたのすべての答えに賛成です)。

AlexRが推測したものを追加し、jDTOとApache Commonsをチェックした後(最終的には一般的な概念が非常に似ていることがわかりました)、オブジェクト階層とメタデータが与えられて機能しているため、他のツールを使用する代わりにコードに固執することにしましたソリューションの構造であり、これまでのところ例外はありません。コードは2回目の編集のものであり、最終的にトリックを実行したヘルパークラスに配置しました。

4

3 に答える 3

3

Apache Commons Bean Utils で問題が解決する場合があります: http://commons.apache.org/beanutils/

すべてのプロパティをコピーする場合は、copyProperties を使用してみてください: http://commons.apache.org/beanutils/v1.8.3/apidocs/src-html/org/apache/commons/beanutils/BeanUtils.html#line.134

次の例を見てください: http://www.avajava.com/tutorials/lessons/how-do-i-copy-properties-from-one-bean-to-another.html

    FromBean fromBean = new FromBean("fromBean", "fromBeanAProp", "fromBeanBProp");
    ToBean toBean = new ToBean("toBean", "toBeanBProp", "toBeanCProp");
    System.out.println(ToStringBuilder.reflectionToString(fromBean));
    System.out.println(ToStringBuilder.reflectionToString(toBean));
    try {
        System.out.println("Copying properties from fromBean to toBean");
        BeanUtils.copyProperties(toBean, fromBean);
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }
    System.out.println(ToStringBuilder.reflectionToString(fromBean));
    System.out.println(ToStringBuilder.reflectionToString(toBean));
于 2012-04-24T18:52:11.303 に答える
2

最良のアプローチは、動的プロキシまたは cglib エンハンサーなどのプロキシ オブジェクトを使用することだと思います。これにより、ゲッターとセッターを装飾し、そこでの変更を追跡できます。

それが役に立てば幸い。

于 2012-04-24T18:55:06.553 に答える
1

あなたのアプローチは問題ありませんが、getMethod()よりもはるかに遅いことに注意しinvoke()てください。そのため、コードのパフォーマンスが重要な場合は、おそらくMethodオブジェクトをキャッシュする必要があります。

于 2012-04-24T18:55:33.023 に答える