Pergunta

Dadas duas classes Java, A e B, em que A é geralmente instanciados através de B, tal como:

    A myA = B.createA();

Posso criar uma subclasse de A (vamos chamá-lo SubA) e de alguma forma têm que ser instanciado pelo método B.createA ()?

(Note que eu não posso modificar A e B ....)

Eu sei que nem todos os casos de A são exemplos de SubA, portanto, eu não posso fazer isso:

    SubA mySubA = B.createA();

Da mesma forma, não posso lançá-lo como esta quer:

    SubA mySubA = (SubA) (B.createA());

pela mesma razão -. Ele vai ficar um ClassCastException

Estou sendo denso e esquecendo algo fundamental, ou não há maneira de fazer isso?

(adição tardio: Eu sinto muito, eu deveria ter mencionado que A e B têm cerca de 50 métodos cada, e tudo que eu quero fazer é adicionar uma única propriedade para SubA, junto com um getter e um setter I. 'd prefere não realmente implementar todos os 50 métodos de a para invocar o método correspondente no objeto da superclasse.)

Foi útil?

Solução

Parece que o que você realmente gostaria é modificar o comportamento de ambos os A original e B. Nesse caso, você poderia tentar estender ambas as classes (onde a extensão de B é puramente para especificar um método ligeiramente diferente de fábrica para criar SubAs).

class SubA extends A {
    /** This is the one special aspect of SubA justifying a sub-class.
        Using double purely as an example. */
    private double specialProperty;

    public double getSpecialProperty() { return specialProperty; }
    public void setSpecialProperty(double newSP) { specialProperty = newSP; }

    public SubA() {
        super();
        // Important differences between SubAs and As go here....
        // If there aren't any others, you don't need this constructor.
    }

    // NOTE: you don't have to do anything else with the other methods of
    // A.  You just inherit those.
}

class SubB extends B {
    // Purely for the purposes of a slightly different factory method
    public A createA() {
        return new SubA();
    }

    // Or if you need a static method 
    // (this is usually instead of the first choice)
    public static A createA() {
        return new SubA();
    }
}

Note que, neste ponto, você pode criar um de seus objetos de fábrica SubB e torná-lo parecido com o B original, como assim:

B myNewB = new SubB();
A myA = myNewB.createA();

Ou, se você estiver usando a fábrica estática em vez disso, ele não é tão perto de um jogo (mas perto).

A myA = SubB.createA();

Agora, se você realmente precisa fazer algo com o sub-propriedade, você terá acesso a ele através da interface criança. Ou seja, se você criar o objeto da seguinte forma:

SubA mySubA = SubB.createA();
mySubA.setSpecialProperty(3.14);
double special = mySubA.getSpecialProperty();

Editar para discutir "adição tardia":

Neste ponto, o seu objeto SubA deve ser exatamente o que você quer. Ele herdará os 50 métodos do pai (A) e você pode adicionar sua propriedade adicional para a criança, mais o getter e setter. Mudei o código acima para ilustrar o que quero dizer.

Outras dicas

Isso geralmente é feito através de um proxy:

class SubA extends A {
    private A proxiedClass;

    public SubA(A a) {
        proxiedClass = a;
    }

    public int anyMethodInA() {
        return proxiedClass.anyMethodInA();
    }
}

...

SubA mySubA = new SubA(B.createA());

Fazer isso manualmente é bastante detalhado, assim que a maioria das pessoas utilizam algum tipo de uma biblioteca AOP (como AspectJ) para apenas chamadas de método de interceptação eles estão interessados ??em.

Você pode criar um invólucro em torno dele, com SubA ter um construtor que leva A como parâmetro.

Como esta:

SubA mySubA = new SubA(B.createA());

Uma vez que todas as instâncias do SubA são instâncias de A, você pode atribuí-lo à variável A existente e substituir todos os métodos necessários.

A myA = new SubA(B.createA());

Eu não posso pensar de qualquer outra maneira limpa de fazê-lo.

Se você está apenas querendo adicionar um campo para A sem orientada a objetos tais como mudança de comportamento, você pode adicioná-lo como um "campo externo". Use um WeakHashMap para mapear de instância de A sobre o valor do campo (contanto que o valor do campo não direta ou indiretamente A referência ou você vai ter um problema de vida do objeto tempo de contenção):

private static final Map<A,FieldType> map =
    new java.util.WeakHashMap<A,FieldType>(); // thread-safe from 1.6, IIRC

public static FieldType getField(A a) {
    return map.get(a);
}
public static void setField(A a, FieldType value) {
    map.set(a, value);
}

Realmente devemos estar usando WeakIdentityHashMap, mas não existe na biblioteca Java!

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