Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/400.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 模式创建具有依赖约束的多态对象_Java - Fatal编程技术网

Java 模式创建具有依赖约束的多态对象

Java 模式创建具有依赖约束的多态对象,java,Java,首先,我的结构: 抽象对象 --ObjectA --反对意见 AbstractOtherObject --其他对象a --其他对象b 使用多态性,我想基于我的AbstractObject创建一个AbstractOtherObject。更准确地说,我想要一个OtherObjectA,如果它是ObjectA,B也是一样。 重要的一点是,我不希望依赖于AbstractObject中的AbstractOtherObject。我无法在AbstractObject中创建抽象方法AbstractOtherOb

首先,我的结构:

抽象对象
--ObjectA
--反对意见

AbstractOtherObject
--其他对象a
--其他对象b

使用多态性,我想基于我的
AbstractObject
创建一个
AbstractOtherObject
。更准确地说,我想要一个
OtherObjectA
,如果它是
ObjectA
,B也是一样。
重要的一点是,我不希望依赖于
AbstractObject
中的
AbstractOtherObject
。我无法在
AbstractObject
中创建抽象方法
AbstractOtherObject-toOtherObject()

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

提前谢谢

更新:伪代码

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

public class Any{
    void do(AbstractObject o){
        AbstractOtherObject otherO = o.toOtherObject();
        doSomething(otherO);
    }
}
但因为我不想要依赖,我只能做一些丑陋的事情,比如:

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

这不是一个完美的解决方案,但它比[IMO]使用
instanceof
更好,是的一种变体

创建
AbstractOtherObjectFactory
抽象类和具体类:
OtherObjectAFactory
OtherObjectBFactory

填充
映射
:将扩展
AbstractOtherObject
的所有可能类映射到它们的相关工厂

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

请注意,
AbstractObject
及其派生类不依赖于任何
AbstractOtherObject
及其派生类,您消除了
instanceof
的使用,但代价是使用
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 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());
(*)请注意,如果您确实需要
A
功能,您仍然需要加入
public OtherA(AbstractObj obj)
。您可以使用访问修饰符确保只能使用其工厂创建
otherA


(*)此解决方案并不完美,但应该可以工作。一个更好的解决方案显然是创建一个
createOtherObj()
方法,正如您所提到的-但是它需要依赖于
AbstractotherObject

访问者模式来拯救

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 {

}
如果无法向具体类添加任何内容,则需要将它们包装在类型感知的可访问包装器中

编辑: 要获得转换后的其他对象,有两种可能的解决方案。您可以将访问者设置为statefull(见上文)。或者,如果需要acceptor方法返回值,则可以使用通用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");
        }

    }
}
Visitor和Visitable现在是通用的:

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

interface Visitable {
    <T> T accept(Visitor<T> v);
}
界面访问者{
T访问(A);
T访问(B);
T访问(可访问);
}
界面可访问{
不接受(访客v);
}
ConvertServiceSitor是抽象的,并且在每种类型的基础上被子类化为具体的访问者:

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

}
抽象类ConverterVisitor实现Visitor{
公众T访问(可访问){
抛出新的IllegalArgumentException(“类型:“+visitable.getClass().getName()+”不受支持”);
}
公众参观(可参观){
回访((可访问)可访问);
}
公众T访问(B可访问){
回访((可访问)可访问);
}
}
类AConverterVisitor扩展了ConverterVisitor{
@凌驾
公众访问(A){
返回新的AOther();
}
}
A和B的accept方法现在的实现方式如下:

A级扩展Abs{

public <T> T accept(Visitor<T> v) {
    return v.visit(this);
}
public <T> T accept(Visitor<T> v) {
    return v.visit(this);
}
public不接受(访客v){
回访(本);
}
}

B类扩展了Abs{

public <T> T accept(Visitor<T> v) {
    return v.visit(this);
}
public <T> T accept(Visitor<T> v) {
    return v.visit(this);
}
public不接受(访客v){
回访(本);
}
}


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

一些关于如何使用这些类的伪代码可能会有所帮助。至少我很难理解您真正想要的是什么。如果您不依赖AbstractObject中的AbstractOtherObject,就无法从AbstractObject返回AbstractOtherObject。我觉得这很好,因为您可以在
a
B
包中使用
Visitor
界面,以及
AOther
world
包中的
ConverterVisitor
。但是,您确实需要取回新的
AOther
实例。因此,访问者中的visit方法返回一个
AOther
,并且您具有依赖关系。添加了泛型版本,以及如何将转换器实现为状态完整转换器。见编辑,谢谢。我认为statefull转换器应该可以工作,但在我的情况下不能使用泛型转换器,因为我首先不知道我是在
a
实例还是
B
实例上调用
.accept
。我会尽快测试你的第一个解决方案。您使用预先构造的映射来避免ifs语句,并且使用键而不是instanceof。这是更好的,但这是同样有缺陷的概念。也许没有其他解决办法。无论如何,谢谢。@D0m3我同意这个解决方案有它的问题。。但这是我能想到的最好的遵守“不依赖约束”的办法。我等了一会儿看是否还有其他答案,否则我会选择你的。