0

我有一个抽象类X和一些扩展这个类的类,称它们A为.BC

在其他一些类Y中,我有一些方法调用取决于类的类型。if-else 语句如下所示:

public class Y implements InterfaceY {

    public Y(){
    }

    public String doStuff (X x, Boolean flag) {
    String s = "";
    if (x instanceof A) {
        doStuff((A) x));
    } else if (x instanceof B) {
        doStuff((B) x));
    } else if (x instanceof C) {
        doStuff((C) x, flag); 
    } else {
        throw new Exeption();
    }
    return s;

    private String doStuff(A a) {
        return "";
    }

    private String doStuff(B b) {
        return "";
    }

    private String doStuff(C c, Boolean flag) {
        return "";
    }
}

请注意,所有方法都具有相同的名称 ( doStuff()),但根据类(有时是标志)调用该方法的不同方法实现。当然,一旦从 X 扩展的类别增加,这看起来很可怕并且变得非常复杂。

有什么方法可以让我以某种方式创建一个中间接口(或其他接口)来处理大部分(或全部)if-else 语句?

4

6 回答 6

1

先把这些方法从这里取出来,分别放到A、B、C类中,实现X接口。

private String doStuff(A a) {
    return "";
}

private String doStuff(B b) {
    return "";
}

private String doStuff(C c, Boolean flag) {
    return "";
}

然后:

if (x instanceof A) {
    doStuff((A) x));
} else if (x instanceof B) {
    doStuff((B) x));
} else if (x instanceof C) {
    doStuff((C) x, flag); 

可以只是x.doStuff();(您甚至不必传递 A、B、C,因为这将this在方法内部。您必须根据您的代码更具体地处理的标志。例如,其他 2doStuff种方法也可以接受标志,但忽略它)

于 2013-09-19T14:56:49.817 回答
0

一些双重调度怎么样?

class X {
    public String letYdoStuff(Y y, Boolean flag) {
        return y.doStuff(this, flag);
    }

    public static void main(String [] args) {
        //X x = new A();
        X x = new B();
        Y y = new Y();

        y.doStuff(x, false);
    }

    public X getThis() {
        return this;
    }
}

class A extends X {
    public String letYdoStuff(Y y, Boolean flag) {
        return y.doStuff(this, flag);
    }
}
class B extends X {
    public String letYdoStuff(Y y, Boolean flag) {
        return y.doStuff(this, flag);
    }
}
class C extends X {
    public String letYdoStuff(Y y, Boolean flag) {
        return y.doStuff(this, flag);
    }
}

class Y {
    public Y(){
    }

    public String doStuff (X x, Boolean flag) {
       String s = "";

       return x.letYdoStuff(this, flag);
   }

   public String doStuff(A a, Boolean flag) {
       System.out.println("in A");
       return "";
   }

   public String doStuff(B b, Boolean flag) {
       System.out.println("in B");
       return "";
   }

   public String doStuff(C c, Boolean flag) {
       System.out.println("in C");
       return "";
   }
}
于 2013-09-19T15:02:20.237 回答
0

分离 a DoStuffOperation,创建相关工厂并使用它们。

  public interface DoStuffOperation<T> {
    String doStuff(T x);
  }
  public class ADoStuffImpl implements DoStuffOperation<A> {
    public String doStuff(A x) {
      return "doStuff<A>";
    }
  }
  public class ADoStuffWithFlagImpl implements DoStuffOperation<A> {
    public String doStuff(A x) {
      return "doStuffWithFlag<A>";
    }
  }
  public class DoStuffImplFactory {
    public final static <T extends X> DoStuffOperation<X> getDoStuff(Class<T> xClass,boolean flag)  {
      DoStuffOperation<X> impl = null;

      if(xClass.equals(A.class))
      {
        if(flag)
          impl = (DoStuffOperation)new ADoStuffWithFlagImpl();
        else
          impl = (DoStuffOperation)new ADoStuffImpl();
        }
      }
      return impl;
    }
  }

  public class Y implements InterfaceY {
    public String doStuff (X x, Boolean flag) {
      return DoStuffImplFactory.getDoStuff(x.getClass(),flag).doStuff(x);
  }
}

通过这种方式,您不必重构对Y.doStuff()orX和派生类的调用。除非类实现了 DoStuffCreator 接口,否则您根本无法删除某种类型instanceof来决定使用哪个实现:doStuff()X

interface DoStuffCreator {
  DoStuffOperation getDoStuffOperation(boolean flag);
}

X是你的A课。您也可以使用反射或其他自动方式(外部属性文件等)构建。

于 2013-09-20T08:20:46.050 回答
0

方法 1

使用状态模式。它可以解决您的问题并消除ifs 和elses。

这是java示例

状态模式将方法调用委托给实现相同接口但行为不同的对象。

状态模式示例:

public class StatePatternExample {
    public static void main(String[] args) {
        Girlfriend anna = new Girlfriend();
                            // OUTPUT
        anna.kiss();        // *happy*
        anna.greet();       // Hey, honey!
        anna.provoke();     // :@
        anna.greet();       // Leave me alone!
        anna.kiss();        // ...
        anna.greet();       // Hey, honey!
    }
}

interface GirlfriendInteraction extends GirlfriendMood {
    public void changeMood(GirlfriendMood mood);
}

class Girlfriend implements GirlfriendInteraction {
    private GirlfriendMood mood = new Normal(this);

    public void provoke() {
        mood.provoke();
    }
    public void kiss() {
        mood.kiss();
    }
    public void greet() {
        mood.greet();
    }
    public void changeMood(GirlfriendMood mood) {
        this.mood = mood;
    }
}

interface GirlfriendMood {
    public void provoke();
    public void kiss();
    public void greet();
}

class Angry implements GirlfriendMood {
    private final GirlfriendInteraction context;

    Angry(GirlfriendInteraction context) { // more parameters, flags, etc. possible
        this.context = context;
    }
    public void provoke() {
        System.out.println("I hate you!");
    }
    public void kiss() {
        System.out.println("...");
        context.changeMood(new Normal(context));
    }
    public void greet() {
        System.out.println("Leave me alone!");
    }
}

class Normal implements GirlfriendMood {
    private final GirlfriendInteraction context;

    Normal(GirlfriendInteraction context) {
        this.context = context;
    }

    public void provoke() {
        System.out.println(":@");
        context.changeMood(new Angry(context));
    }

    public void kiss() {
        System.out.println("*happy*");
    }

    public void greet() {
        System.out.println("Hey, honey!");
    }
}

如您所见,该类Girlfriend没有ifs 和elses。它看起来很干净。

Girlfriend对应于你的abstract class X,类NormalAngry对应于ABC

然后,您的班级Y直接委托给 X 而不检查任何情况。

方法 2

使用命令模式。然后,您可以将命令对象移交给YsdoStuff()方法并执行它。

于 2013-09-19T14:48:00.530 回答
0

实现一个Handler接口然后按支持的类型映射它怎么样:

public interface Handler<T extends X>{
     Class<T> supportedClass;

     void doStuff(T value, Object...args);
}


public class Y implements InterfaceY {

       private Map<Class<?>, Handler<?>> handlers;

      public Y(List<Handler<?>> handlers){
          // populate map
      }


      public void process(X value){
           handler.get(value.getClass).doStuff(X, ...);
           // you would have to figure out how to determine when other values are needed
      }
}
于 2013-09-19T14:48:03.217 回答
0

这可能是一个难题。我认为 Cruncher 的解决方案,添加 到 X 并在, ,doStuff中覆盖它是最简单和最好的解决方案,如果合适的话。但是,由于单一责任原则,它并不总是合适的。(我认为这是正确的术语。如果我弄错了一些术语,我深表歉意,我并不完全了解所有术语。)ABC

这个想法是,doStuff如果X它与X. 如果X并且Y是同一个“团队”的一部分,即它们都被设置为服务于一个特定应用程序的目的,那么它可能没问题。

但是假设您有一个具有子类、、、等的抽象Shape类 。将有一些属于该类的方法,这些方法对使用该类的任何应用程序都很有用。但是现在假设您正在编写一个使用其中一些形状的游戏,并且您想要一个多态操作来确定当形状被飞猴吃掉时会发生什么。你不会想在 你的类中添加一个抽象方法,即使这个类是你自己创建的,而不是在别人的库中,因为这对于一个通常可以用于除此之外的其他目的的类来说太具体了游戏。CircleSquareUndecagonRandomBlobShapeShapecomputeEatenByFlyingMonkeyShape

我可以想到几种方法来解决这个问题。

如果不适合(或不可能)添加doStuffX,但如果ABC与您的应用程序更紧密地连接,以便添加doStuff到它们是合适的,您可以添加另一个类:

public abstract class XWithStuff extends X {
    // repeat any constructors in X, making them all be just
    // calls to super(...)
    public abstract void doStuff (Boolean flag);
}

public class A extends XWithStuff {
    @Override
    public void doStuff (Boolean flag) { ... }
}

以此类推。(XWithStuff只是一个示例名称;在现实生活中,包含“X”和一些对应用程序或目的的引用的名称可能会更好。)(PS 我不知道你为什么使用Boolean而不是,boolean但我如果有充分的理由,请保持这种状态。)

doStuff如果添加到AB和也不合适或不可能C,这里有一个可能的解决方案:

public interface StuffInterface {
    public void doStuff (Boolean flag);
}

public class AWithStuff extends A implements StuffInterface {
    @Override
    public void doStuff (Boolean flag) { ... }
}

然后在您的程序中创建类对象AWithStuff而不是A等。doStuff调用X

void doStuff (X x, Boolean flag) {
    if (x instanceof StuffInterface)  {
        ((StuffInterface) x).doStuff (flag);
    } else {
        throw new IllegalArgumentException ();
    }
}

如果这不是一个选项并且您必须直接处理A,B等,并且您无法添加doStuff到这些类中,那么任何解决方案都会有点笨拙。如果您不想使用if- then- else,您可以查看访问者模式,或者您可以想象创建一个HashMap<Class<?>,Interf>将 , 等映射A.classB.class调用正确doStuff. 但我还没有弄清楚细节。(实际上,“访问者模式”可能不合适,除非你有某种由 X 类型的对象组成的复杂结构。)

于 2013-09-19T16:10:28.747 回答