根据 Java 中 Object 的类型选择实现

Xel*_*ian 2 java design-patterns strategy-pattern visitor-pattern genetic-algorithm

我有一个父类型

public class IObject{}
Run Code Online (Sandbox Code Playgroud)

并且可以有很多子类(甚至是未来的新子类)

public class Object1 extends IObject{}
public class Object2 extends IObject{}
public class Object3 extends IObject{}
...
public class ObjectN extends IObject{}
Run Code Online (Sandbox Code Playgroud)

然后根据这些对象的类型我必须做不同的操作。

public class StrategyForObject1(){void do{}}
public class StrategyForObject2(){void do{}}
public class StrategyForObject3(){void do{}}
...
public class StrategyForObjectN(){void do{}}
Run Code Online (Sandbox Code Playgroud)

所以我想从我的 Context 类:

   public Conext {
    IObject o;

    public void setObject(IObject o) {
        this.o = o;
    }

    void logic() {
        if (o instanceOf Object1) {
            new StrategyForObject1().do();
        }
        if (o instanceOf Object2) {
            new StrategyForObject2().do();
        }
        if (o instanceOf Object3) {
            new StrategyForObject3().do();
        }
        ...
        if (o instanceOf ObjectN) {
            new StrategyForObjectN().do();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,基于执行不同算法的类型,但如果我需要添加新的子类IObject只是为了添加新StrategyForObject**N**类,而不是更改类,我希望像策略模式一样可扩展Conext。在策略模式中,我们必须指定策略,但在这里我们必须做相反的事情:根据对象的类型选择策略。如何以最好的方式在 Java 中做到这一点?

编辑IObject无法更改以添加其他方法。我必须将逻辑与数据分开,因此Object1例如在类中添加逻辑的实现是不可取的。

Uli*_*ses 5

我认为您需要实现访问者模式。基本上,对于你所拥有的,它看起来像这样:

interface IObjectVisitor {
    void visit(IObject1 obj1);
    void visit(IObject2 obj2);
    ...
    void visit(IObjectN objN);
}    
interface IObjectVisitable {
    void accept(IObjectVisitor visitor);
}
public abstract class IObject implements IObjectVisitable {
   ...
}
public class IObject1 extends IObject {
    public void accept(IObjectVisitor visitor) {
        visitor.visit(this);
    }
}
public class IObject2 extends IObject {
    public void accept(IObjectVisitor visitor) {
        visitor.visit(this);
    }
}
...
public class IObjectN extends IObject {
    public void accept(IObjectVisitor visitor) {
        visitor.visit(this);
    }
}
public class SomeLogicIObjectVisitor implements IObjectVisitor {
    void visit(IObject1 obj1) {
        //something with obj1
    }
    void visit(IObject2 obj2) {
        //something with obj2
    }
    ...
    void visit(IObjectN objN) {
        //something with objN
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你有一些逻辑可以应用到一些 IObject 像这样:

public void someLogic(IObject obj) {
    SomeLogicIObjectVisitor visitor = new SomeLogicIObjectVisitor():
    visitor.visit(obj);
}
Run Code Online (Sandbox Code Playgroud)

面向对象明智,这是您可以实现的最佳模式。原因是因为它允许您采用模块化和可扩展的方法,应用正确的关注点分离。例如,看看@nhouser9 提供的答案。虽然abstract void do();在 IObject 中定义乍一看似乎有效,但您会将业务逻辑嵌入到域对象中,而域对象很可能不属于那里。此外,如果现在您考虑其他一些逻辑,我们将其称为“logic2”,现在您别无选择,只能abstract void do2();在每个 IObject 实现上创建,并继续在其中嵌入业务逻辑。使用访问者模式,IObject 实现不会改变,并且您不会在 IObject 中嵌入任何逻辑,只需创建一个新访问者,Logic2IObjectVisitor并在那里实现每个 IObject 实现的逻辑。你会这样称呼它:

public void someLogic2(IObject obj) {
    Logic2IObjectVisitor visitor = new Logic2IObjectVisitor():
    visitor.visit(obj);
}
Run Code Online (Sandbox Code Playgroud)