Pergunta

Eu estive procurando uma maneira genérica para lidar com associações bidirecionais e uma maneira de lidar com as atualizações inversas no manual do código Java escrito.

Para aqueles que não sabem o que eu estou falando, aqui está um exemplo. Abaixo estão os meus resultados atuais de soluções (insatisfatório).

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

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

Agora, quando atualizar qualquer extremidade da associação, a fim de manter a consistência, a outra extremidade deve ser atualizado também. Manualmente cada vez

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

ou colocando o código correspondente na setter / getter e usar uma implementação de lista personalizada.

Eu encontrei um projeto desatualizado, não mantido cujas dependências não estão mais disponíveis ( https: //e-nspire-gemini.dev.java.net/ ). Ele lida com o problema usando as anotações que são usados ??para injetar o código necessário automaticamente.

Alguém sabe de uma outra estrutura que lida com isso de uma maneira genérica, discreto ala gemeos?

ciao, Elmar

Foi útil?

Solução

O Google coleções (de código interno do google) - http://code.google. com / p / google-coleções / é Java generics compatíveis (não só é compatível, usos genéricos muito bem)

Class bitmap - 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 permite Associações bidirecionais.

são esperados Algumas destas classes para fazer o seu caminho para o JDK 7.

Outras dicas

A menos que você abstrair os setters, você vai ter que fornecer algum tipo de mecanismo de notificação de eventos. Se seus objetos são JavaBeans, então você está olhando para usar PropertyChangeSupport e disparando eventos de alteração de propriedade.

Se você fizer isso (ou tem algum outro mecanismo para detecção de alterações), então Listas envidraçadas fornece uma ObservableElementList que poderia facilmente ser usado para lidar com a sincronização de associação a partir do final da lista (ou seja, a adição de um para List chama automaticamente a.setB (b)) . A outra direção é facilmente manipulado usando mudança de propriedade monitoramento (ou equivalente).

Sei que esta não é uma solução genérica, mas parece que seria uma base fácil para um.

Note que algo como isso seria requerem a implementação da lista especial na classe B - nenhuma maneira curta de soluções tipo AOP que você poderia lidar com isso no caso geral (ou seja, utilizando ArrayList ou algo parecido ).

Gostaria também de salientar que o que você está tentando alcançar é algo do santo graal da ligação de dados. Existem algumas implementações decentes para ligação a nível de campo (coisas como getters e setters) (ver JGoodies ligação e JSR 295 para exemplos). Há também um realmente bom implementação para o tipo de lista vinculativa (Listas de vidro, referido acima). Nós usamos duas técnicas em conjunto com os outros em quase todas as nossas aplicações, mas nunca tentou ir tão abstrato como o que você está perguntando.

Se eu estivesse projetando isso, eu iria olhar para algo como isto:

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

Connector é uma interface que permite a uma única interface para vários tipos de notificação de alteração. Synchronizer é uma interface que é chamado para garantir que ambos os objetos estão em sincronia sempre que um deles é alterado.

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

ChangeInfo fornece dados sobre qual membro mudou, e que as mudanças realmente eram. Estamos. Se você está tentando realmente manter este genérico, então você praticamente tem que chutar a implementação deste até o usuário quadro.

Com o acima no lugar, seria possível ter um número de conectores e sincronizadores pré-definidos que critérios vinculativos atender diferentes.

Curiosamente, a assinatura do método acima é bastante semelhante à chamada de método JSR 295 createAutoBinding (). objetos de propriedade são o equivalente a Connector. O JSR 295 não tem o sincronizador (em vez disso, eles têm uma estratégia de ligação especificado como um ENUM - mais JSR 295 funciona somente com ligação propriedade-> propriedade, tentando ligar um valor de campo de um objeto para a associação da lista desse objeto em outro objeto não é mesmo sobre a mesa para eles).

Para fazer sentido, essas calsses será pares. Eu sugiro um mecanismo de pacote-privadas (na ausência de amigo) para manter a consistência.

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);
    }
}

(Disclaime:. Não testado ou mesmo compilado)

Na maior parte segura exceção (pode vazar em caso de exceção). Segmento de segurança, muitos-muitos, desempenho, libraryisation, etc., é deixado como um exercício para o leitor interessado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top