我一直在寻找处理双向关联的通用方法,以及在手动编写的Java代码中处理逆更新的方法。

对于那些不知道我在说什么的人,这是一个例子。下面是我目前的(不满意的)解决方案的结果。

public class A {
    public B getB();
    public void setB(B b);
}

public class B {
    public List<A> getAs();
}

现在,在更新关联的任何一端时,为了保持一致性,另一端也必须更新。每次手动

a.setB(b);
b.getA().add(a);

或通过在setter / getter中放置匹配代码并使用自定义List实现。

我发现了一个过时的,未维护的项目,其依赖项不再可用( https: //e-nspire-gemini.dev.java.net/ )。它通过使用用于自动注入必要代码的注释来处理问题。

是否有人知道另一个框架以一种通用的,不引人注目的方式处理这个问题?

侨, 艾玛

有帮助吗?

解决方案

google collections(来自谷歌的内部代码) - http://code.google。 com / p / google-collections / 兼容Java Generics(不仅兼容,使用泛型非常好)

类BiMap - http://google-collections.googlecode.com/svn/trunk/javadoc/index.html?http://google -collections.googlecode.com/svn/trunk/javadoc/com/google/common/collect/package-summary.html 允许双向关联。

预计其中一些课程将进入JDK 7。

其他提示

除非你抽象出setter,否则你将不得不提供某种事件通知机制。如果您的对象是JavaBeans,那么您正在考虑使用PropertyChangeSupport并触发属性更改事件。

如果您这样做(或者有一些其他机制来检测更改),那么Glazed Lists会提供 ObservableElementList ,可以很容易地用来处理列表端的关联同步(即自动添加A到List <!> lt; A <!> gt;调用a.setB(b))。使用属性更改监控(或等效)可以轻松处理另一个方向。

我意识到这不是一个通用的解决方案,但它似乎是一个简单的基础。

请注意,像这样的东西需要 B类中的特殊列表实现 - 没有办法在一般情况下可以处理它的AOP类型解决方案(即使用ArrayList或类似的东西) )。

我还应该指出,你想要实现的是数据绑定的圣杯。在字段级别有一些不错的绑定实现(像getter和setter这样的东西)(参见JGoodies binding和JSR 295的例子)。列表类型绑定还有一个非常好的实现(Glazed Lists,如上所述)。我们几乎在所有应用程序中都使用这两种技术相互协调,但从未尝试过像您所要求的那样抽象。

如果我正在设计这个,我会看一下这样的事情:

AssociationBuilder.createAssociation(A a, Connector< A> ca, B b,  Connector< B> cb, Synchronizer< A,B> sync)

Connector是一个接口,允许单个接口用于各种更改通知类型。 Synchronizer是一个被调用的接口,用于确保两个对象在其中一个对象发生更改时保持同步。

sync(ChangeInfo info, A a, B b) // make sure that b reflects current state of a and vice-versa.  

ChangeInfo提供有关更改了哪个成员以及实际更改内容的数据。我们是。如果你试图真正保持这种通用性,那么你几乎不得不将这个实现归功于框架用户。

有了上述内容,就可以拥有许多符合不同绑定标准的预定义连接器和同步器。

有趣的是,上面的方法签名非常类似于JSR 295 createAutoBinding()方法调用。属性对象相当于Connector。 JSR 295没有Synchronizer(相反,它们有一个绑定策略指定为ENUM - 加上JSR 295仅适用于属性 - <!> gt;属性绑定,试图将一个对象的字段值绑定到该对象的列表另一个对象的成员资格甚至不在他们的桌面上。)

有意义的是,这些calsses将是同行。我建议使用包私有机制(在朋友的缺席中)以保持一致性。

public final class A {
    private B b;
    public B getB() {
        return b;
    }
    public void setB(final B b) {
        if (b == this.b) {
            // Important!!
            return;
        }
        // Be a member of both Bs (hence check in getAs).
        if (b != null) {
            b.addA(this);
        }
        // Atomic commit to change.
        this.b = b;
        // Remove from old B.
        if (this.b != null) {
            this.b.removeA(this);
        }
    }
}

public final class B {
    private final List<A> as;
    /* pp */ void addA(A a) {
        if (a == null) {
            throw new NullPointerException();
        }
        // LinkedHashSet may be better under more demanding usage patterns.
        if (!as.contains(a)) {
            as.add(a);
        }
    }
    /* pp */ void removeA(A a) {
        if (a == null) {
            throw new NullPointerException();
        }
        as.removeA(a);
    }
    public List<A> getAs() {
        // Copy only those that really are associated with us.
        List<A> copy = new ArrayList<A>(as.size());
        for (A a : as) {
            if (a.getB() == this) {
                copy.add(a);
            }
        }
        return Collection.unmodifiableList(copy);
    }
}

(声明:未经测试甚至编译。)

大多数异常安全(在例外情况下可能泄漏)。线程安全,许多,性能,库化等等,都留给感兴趣的读者练习。

感谢所有建议。但没有一个接近我所寻找的东西,我可能以错误的方式提出了这个问题。

我一直在寻找gemini的替代品,所以想要以一种不引人注目的方式处理它,而不会通过无限的检查和特殊的List实现来污染代码。正如凯文所建议的那样,这当然要求基于AOP的方法。

当我再看一遍时,我在cnet上发现了一个包含所有源和依赖源的gemini包。依赖项缺失的来源是阻止我使用它的唯一问题。从现在开始,所有来源都可以修复。 如果有人查找: http://www.download.com/Gemini /3000-2413_4-10440077.html

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top