2009-04-30 74 views
2

鉴于两个Java类,A和B,其中A通常是利用B实例化的,如:如何扩展由另一个类实例化的java类?

A myA = B.createA(); 

我可以创建一个(我们称之为苏巴)一个子类,莫名其妙地就被实例化B.createA()方法?

(请注意,我不能修改A和B ....)

我知道,不是所有实例都苏巴的情况,因此,我不能做到这一点:

SubA mySubA = B.createA(); 

同样,我不能这样做:

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

出于同样的原因 - 它会得到一个ClassCastException。

我是密集的,忘记了一些根本性的东西,还是没有办法做到这一点? (后期补充:我非常抱歉,我应该提到A和B各有大约50种方法,我想要做的就是向SubA中添加一个属性,以及一个getter和setter。我真的宁可不落实的的方法都50来调用父类的对象相应的方法)

回答

3

这听起来像你最喜欢的是修改原来的AB的行为。在这种情况下,您可以尝试扩展这两个类(其中B的扩展名纯粹是为了指定创建SubA的稍微不同的工厂方法)。

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

注意,在这一点上,你可以创建你SubB工厂对象之一,使它看起来像原来B像这样:

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

或者,如果您使用的是静态工厂相反,它不是非常接近(但它很接近)。

A myA = SubB.createA(); 

现在,如果你真的需要做的子属性的东西,你必须通过子接口访问它。也就是说,如果您创建对象,像这样:

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

编辑讨论“后加”:

在这一点上,你的苏巴对象应该是正是你想要的。它将继承父(A)中的50个方法,并且可以将您的附加属性添加到子项以及getter和setter。我改变了上面的代码来说明我的意思。

+0

对于我在我的问题中给出的有限信息,这绝对是对它的回答。我将不得不做一些挖掘和一些实验,看看它是否在我所处的真实情况下工作,但我很肯定这个答案! – Scott 2009-04-30 23:58:39

3

这通常是通过代理完成。

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

手动执行此操作相当冗长,因此大多数人使用某种类型的AOP库(如AspectJ)来截获他们感兴趣的方法调用。

+0

严格来说,这更像是一个装饰器而不是代理器。 http://en.wikipedia.org/wiki/Decorator_pattern – 2009-04-30 01:01:53

+0

如果你需要引用A的私人领域或方法会怎样? – 2009-04-30 02:30:04

1

您可以创建一个包装,SubA具有一个构造函数以A为参数。

像这样:

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

由于SubA所有实例都是A情况,然后你可以将其分配给现有的A变量,并覆盖任何必要的方法。

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

我想不出任何其他干净的做法。

1

如果你只是想添加一个字段到A没有面向对象,如改变行为,你可以将它添加为“外部字段”。使用WeakHashMapA的实例映射到字段值(只是只要字段值不直接或间接地引用A或者你有一个对象寿命争的问题):

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

真的我们应该使用WeakIdentityHashMap,但它不存在于Java库中!

相关问题