【问题标题】:How to abstract different return types in Java?如何在 Java 中抽象出不同的返回类型?
【发布时间】:2014-06-27 06:05:31
【问题描述】:

我猜这是某种设计模式问题。

我想将几个操作(输入 + 处理逻辑 + 输出)建模为实现一些 IOperation 接口的类。

每个操作可能有不同的输入参数和不同的输出参数。

我可以使用每个操作的构造函数为每个操作指定不同的输入。

但我也希望以正交方式为每个类获得不同的输出,而不必将接口转换为具体类。

对此的明显方法是 [1] 转换为具体类并调用返回所需结果的特定方法或 [2] 将结果包装到某个 OperationResult 对象中,这反过来也需要向下转换或一些元数据信息 + 提取器代码。

我想避免处理反射或向下转换或元数据解释。

在 Java 中是否有针对这种情况的已知设计?对此有什么好的方法?

更新 - @Laf,这里有一些具体的例子。我想提取“c”

interface IOperation{
    void execute();
}

public class AddOp implements IOperation{

    private int a;
    private int b;
    private int c;

    public AddOp(int a, int b){
        this.a = a;
        this.b = b;
    }

    @Override
    public void execute() {
        this.c = this.a + this.b;
    }

}

public class AndOp implements IOperation{

    private boolean a;
    private boolean b;
    private boolean c;

    public AndOp(boolean a, boolean b){
        this.a = a;
        this.b = b;
    }

    @Override
    public void execute() {
        this.c = this.a && this.b;
    }

}

【问题讨论】:

  • 你考虑过使用泛型吗?
  • 听起来不错。 @Laf 你对泛型的方法是什么?
  • 回答 Noor,这是真的,但如果我在此接口中没有针对每种不同类型结果的方法,我将不得不将其向下转换为具体实现。 (-1 不是我 - 我不会对自己的问题答案投反对票)
  • 如果没有您提供的任何代码示例,很难编写出完全符合您需求的解决方案。但是如果你有一个接口InputParameter<String,V>,其中第一个参数是名称,第二个参数是任何类的值,那么它可能会解决你的问题。
  • @Laf 提供示例

标签: java design-patterns


【解决方案1】:

看起来你可以使用double dispatching

您返回 void 并作为参数传递您希望将结果放入的目标对象,而不是返回值(即 Object)。

interface ResultProcessor {
    processTypeA(A item);
    processTypeB(B item);
    processTypeC(C item);
}

interface InputProcessor {
    processInput(ResultProcessor target);
}

class ConcreteInputProcessorA {
    processInput(ResultProcessor target) {
      A result = ...; // Do something
      target.processTypeA(result);
    }
}

class ConcreteInputProcessorB {
    processInput(ResultProcessor target) {
      B result = ...; // Do something
      target.processTypeB(result);
    }
}

class ConcreteInputProcessorC {
    processInput(ResultProcessor target) {
      C result = ...; // Do something
      target.processTypeC(result);
    }
}

更新:例如,您可以编写新编辑的代码:

public class AddOp implements IOperation{

    private int a;
    private int b;
    private int c;

    public AddOp(int a, int b){
        this.a = a;
        this.b = b;
    }

    @Override
    public void execute(Executor ex) {
        this.c = this.a + this.b;
        ex.executeAddOp(this);
    }
}

public class Executor {
    public void executeAddOp(AddOp op) {
        System.out.println("Executing an AndOp... " + op);
    }
}

【讨论】:

  • 是的,访问者模式的后半部分来拯救 :-)
  • @vz0 这听起来确实不错。就我而言,我希望每个实现 ResultProcessor 的类只实现一个方法。我怎么能强制执行呢?为所有其他类型抛出“不受支持”的异常?
  • @vz0 而不是分别处理输入和输出,自己处理操作...别出心裁
【解决方案2】:

在考虑了此处发布的一些建议后,我自己想到了另一种有趣的方法。

我不会接受它作为最终答案,因为我认为这对于那些花时间试图提供帮助的人是不公平的。但我还是想分享它。

public class SO {

    public static void main(String[] args){
        new SO().new Example().exec();
    }

    interface IResponse{
        //just a tagging interface
    }

    public class IntegerResponse implements IResponse{
        private int i;

        private IntegerResponse(int i) {
            this.i = i;
        }

        protected int getI() {
            return i;
        }

    }

    public class BooleanResponse implements IResponse{
        private boolean b;

        private BooleanResponse(boolean b) {
            this.b = b;
        }

        protected boolean isB() {
            return b;
        }

    }

    interface IOperation<X extends IResponse>{
        void execute();
        <X extends IResponse> X someMethod();
    }



    public class AddOp implements IOperation<IntegerResponse>{

        private int a;
        private int b;
        private int c;

        public AddOp(int a, int b){
            this.a = a;
            this.b = b;
        }

        @Override
        public void execute() {
            this.c = this.a + this.b;
        }

        @SuppressWarnings("unchecked")
        @Override
        public IntegerResponse someMethod() {
            return new IntegerResponse(this.c);
        }

    }

    public class AndOp implements IOperation<BooleanResponse>{

        private boolean a;
        private boolean b;
        private boolean c;

        public AndOp(boolean a, boolean b){
            this.a = a;
            this.b = b;
        }

        @Override
        public void execute() {
            this.c = this.a && this.b;
        }

        @SuppressWarnings("unchecked")
        @Override
        public BooleanResponse someMethod() {
            return new BooleanResponse(this.c);
        }

    }

    public class Example{
        public void exec(){
            IOperation<?> op = new AndOp(true,false);
            BooleanResponse resp = op.someMethod();
            System.out.println(resp.isB());
        }
    }
}

【讨论】:

    【解决方案3】:

    一种可能的方法是这样的:

    private <T extends SomeCommonAncestor> T someMethod(InputParamObject i,
            Class<T> respClass)  {...}
    

    对于返回的对象,您仍然需要一些通用接口/抽象类,并且您需要将实现/子类指定为方法参数的一部分。

    希望这会有所帮助。

    [编辑]

    public interface IOperation{
    
           public <T extends ResultObject> T execute(Class<T> respClass);
    }
    
    public class AndOp implements IOperation{
    
        private boolean a;
        private boolean b;
        private boolean c;
    
        public AndOp(boolean a, boolean b){
            this.a = a;
            this.b = b;
        }    
    
    
       @Override
       public <T extends ResultObject> T execute(Class<T> respClass)
       {
           BoolWrap ret = new BoolWrap (a & b);
           return ret;
       }
    
    }
    
    class BoolWrap extends ResultObject {
     ...
    }
    
    class AndOpTest {
        public void testIt ()
        {
             AndOp op = new AndOp (false, true);
             BoolWrap result = op.execute (BoolWrap.class);
             //Profit?
        }
    }
    

    【讨论】:

    • 嗨@demaniak,我以前在另一个环境中使用过它,它真的很好用。但我不清楚在这个问题的上下文中我将如何使用它。我已经尝试将此方法添加到 IOperation 但我无法弄清楚如何处理每个具体的操作实现。您打算如何使用此解决方案?谢谢。
    • 谢谢@demaniak。如果可以的话,我会接受你和 vz0 的答案。特别是,您的洞察力对我在这里提出的答案很重要,我真的很喜欢它。但我必须同意 vz0 的回答表明我在尝试分别强制输入和输出时走错了路,而简单的控制反转(我们可以称之为 IoC 吗?)可以以更好的方式工作。所以我想说谢谢你所有的时间。我当然赞成你的回答。谢谢
    猜你喜欢
    • 1970-01-01
    • 2011-12-16
    • 1970-01-01
    • 2014-04-03
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    • 1970-01-01
    • 2017-12-01
    相关资源
    最近更新 更多