用于创建具有依赖性约束的多态对象的模式

时间:2012-03-22 15:23:41

标签: java

首先,我的结构:

AbstractObject
--ObjectA
--ObjectB

AbstractOtherObject
--OtherObjectA
--OtherObjectB

对于多态,我想根据我的AbstractOtherObject创建AbstractObject。更确切地说,如果OtherObjectAObjectA,我需要AbstractOtherObject 重要的是,我不想在AbstractObject中依赖AbstractOtherObject toOtherObject()。我无法在AbstractObject中制作抽象方法public class Any{ void do(AbstractObject o){ AbstractOtherObject otherO = o.toOtherObject(); doSomething(otherO); } }

我找不到不使用 instanceof 的解决方案。

提前致谢。

更新:伪代码

如果我没有依赖性约束,我会这样做:

public class Any{
    void do(AbstractObject o){
        AbstractOtherObject otherO;
        if(o instanceof ObjectA){
            otherO = new OtherObjectA(o);
        } else {
            otherO = new OtherObjectB(o);
        }
        doSomething(otherO);
    }
}

但是因为我不想要依赖,所以我只能做一些丑陋的事情:

{{1}}

2 个答案:

答案 0 :(得分:1)

游客模式救援!

public class VisitorExample {
    public static void main(String[] args) {
        ConverterVisitor converterVisitor = new ConverterVisitor();
        A a = new A();
        B b = new B();
        a.accept(converterVisitor);
        AbsOther aother = converterVisitor.getOther();
        b.accept(converterVisitor);
        AbsOther bother = converterVisitor.getOther();
    }
}

要点是让一个单独的类在这种情况下ConverterVisinor做实际的转换类型之间的工作。

Visitor类需要知道应该访问的不同具体类,但Visitable只需要依赖于Visitor接口。

interface Visitor {
    void visit(A a);
    void visit(B b);
    void visit(Visitable visitable);
}

interface Visitable {
    void accept(Visitor v);
}

因此,在类型之间进行转换的实际工作的访问者看起来像:

class ConverterVisitor implements Visitor {


    // Added field and getter to store the other object in...
    private AbsOther other;

    public AbsOther getOther {
        return other;
    }

    public void visit(B b) {
        System.out.println("Convert a to BOther");
        other = new BOther();
    }

    public void visit(A a) {
        System.out.println("Convert a to AOther");
        other = new AOther();
    }

    @Override
    public void visit(Visitable visitable) {
        throw new IllegalArgumentException("Type: " + 
            visitable.getClass().getName() + " not supported");
    }

}

然后,转换中涉及的抽象类和类可以如下所示:

abstract class Abs implements Visitable { }
abstract class AbsOther { }

class A extends Abs {

    public void accept(Visitor v) {
        v.visit(this);
    }

}

class B extends Abs {

    public void accept(Visitor v) {
        v.visit(this);
    }

}

class AOther extends AbsOther {

}

class BOther extends AbsOther {

}

如果您无法在具体类中添加任何内容,则需要将它们包装在类型识别的可访问包装器中。

修改 要获得转换的其他对象,您有两种可能的解决方案。要么你可以使访问者满意(见上文)。或者,如果您需要使用acceptor方法返回值,则可以使用Generic Visitor / Visitable。

public class VisitorExample {
    public static void main(String[] args) {
        AConverterVisitor converterVisitor = new AConverterVisitor();
        A a = new A();
        B b = new B();
        AOther aother = a.accept(converterVisitor);
        System.out.println("Got AOther!");

        try {
            b.accept(converterVisitor); 
        } catch (IllegalArgumentException iae) {
            System.out.println("Calling accept on b with a AConverterVisitor will result in a exception");
        }

    }
}

访客和可访问现在是通用的:

interface Visitor<T> {
    T visit(A a);
    T visit(B b);
    T visit(Visitable visitable);
}

interface Visitable {
    <T> T accept(Visitor<T> v);
}

ConverterVisitor是抽象的,并且按类型划分给具体访问者:

abstract class ConverterVisitor<T> implements Visitor<T> {

    public T visit(Visitable visitable) {
        throw new IllegalArgumentException("Type: " + visitable.getClass().getName() + " not supported");
    }


    public T visit(A visitable) {
        return visit((Visitable) visitable);
    }


    public T visit(B visitable) {
        return visit((Visitable) visitable);
    }

}

class AConverterVisitor extends ConverterVisitor<AOther> {

    @Override
    public AOther visit(A a) {
        return new AOther();
    }

}

A和B的接受方法现在将实现如下:

A类延伸Abs {

public <T> T accept(Visitor<T> v) {
    return v.visit(this);
}

}

B级延伸Abs {

public <T> T accept(Visitor<T> v) {
    return v.visit(this);
}

}

其他类和抽象类与第一个示例中的相同。

答案 1 :(得分:0)

不是一个完美的解决方案,但它更好[IMO]然后使用instanceof,是abstract factory pattern的变体。

创建AbstractOtherObjectFactory抽象类和具体类:OtherObjectAFactoryOtherObjectBFactory

填充Map<Class,AbstractOtherObjectFactory>:将所有可能扩展AbstractOtherObject的类映射到相关工厂。

当需要创建新对象时使用:map.get(obj.getClass()).build(obj);

请注意AbstractObject及其派生类不依赖于AbstractOtherObject及其派生类中的任何一个,并且消除了instanceof的使用 - 但代价是使用{ {1}}。

示例:
第一类课程:

getClass()

第二类课程:

public abstract static class AbstractObj {
    @Override
    public String toString() {
        return "AbstractObj";
    }
}
public static class A extends AbstractObj {
    @Override
    public String toString() {
        return "A";
    }
}

工厂类:

public abstract static class OtherAbstractObj {
    @Override
    public String toString() {
        return "AbstractObj";
    }
}
public static class OtherA extends OtherAbstractObj {
    public OtherA(AbstractObj obj) { }
    @Override
    public String toString() {
        return "OtherA";
    }
}

填充地图[在程序生命周期内只需要执行一次]:

public static interface Factory {
    public abstract OtherAbstractObj build(AbstractObj obj);
}
public static class OtherAFactory implements Factory {
    @Override
    public OtherAbstractObj build(AbstractObj obj) {
        return new OtherA(obj);
    }
}

从原始对象创建一个新的第二个类型对象:

    Map<Class<? extends AbstractObj>,Factory> map = new HashMap<Class<? extends AbstractObj>, Test.Factory>();
    map.put(A.class, new OtherAFactory());

(*)请注意,如果您确实需要 AbstractObj a = new A(); OtherAbstractObj other = map.get(a.getClass()).build(a); System.out.println(other); 功能,则仍需要投射public OtherA(AbstractObj obj)。您可以使用访问修饰符来确保只能使用其工厂创建A

(*)这个解决方案并不完美,但应该可行。如上所述,更好的解决方案显然是创建otherA方法 - 但它需要依赖于createOtherObj()