有条件地从两个不同的类调用具有相同名称的方法

时间:2020-05-13 18:13:10

标签: java lambda

我想要一个实现,其中需要根据条件从两个类之一中调用一个方法。为了说明这一点,可以说我有两个简单的类:

public class A implements IObject {
    @Override
    public void doIt() {
        System.out.println("OBJECTA");
    }
}
public class B implements IObject {
    @Override
    public void doIt() {
        System.out.println("OBJECTB");
    }
}

和界面

public interface IObject {
    void doIt();
}

我动态调用类函数的方法实现为:

void call(String s, A a, B b, Consumer<IObject> o) {
    if(s.equalsIgnoreCase("CONDITION")) {
        o.accept(a);
    } else {
        o.accept(b);
    }
}

我可以这样称呼该方法

A objectA = new A();
B objectB = new B();

call("CONDITION", objectA, objectB, IObject::doIt);
call("OTHER", objectA, objectB, IObject::doIt);

这实际上将根据条件参数在类doItA上调用B

是否存在一种更清洁的方式来实现这一目标,也许可以减少参数的数量,从而减少功能call的签名?

谢谢

4 个答案:

答案 0 :(得分:2)

据我了解,您的问题:

  • 您有病
  • 您有一个要使用的上下文(对象a和b)
  • 如果您不打算针对多个条件或对象(a,b)来泛化您的代码,则不会提出这样的问题。否则,三元运算符或if将会更容易维护(例如:((condition) a:b).doIt()与下面的代码)。

为什么不使用这样的模式:

A a = new A();
B b = new B();
String hint = ...;

List<Executor> list = new ArrayList<>();
list.add(new Executor("CONDITION"::equalsIgnoreCase, a::doIt));
list.add(new Executor(s -> true, b::doIt));
for (Executor executor : list) {
  if (executor.process(hint)) {
    break; 
  }
}

使用Executor类:

class Executor {
  private final Predicate<String> predicate;
  private final Runnable runnable;
  ...
  public boolean process(String s) {
    if (!predicate.test(s)) {
      return false;
    }  
    runnable.run();
    return true;
  }
}

循环将评估条件,然后运行代码(如果为true),否则继续执行下一个元素。

Executor类在技术上不绑定到ab;只有初始设置。

答案 1 :(得分:2)

这是一种完全不同的方法,利用了java.lang.reflect.Proxy

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 *
 * @author ben
 */
public class Test {

    public interface IObject {
        void doIt();
    }
    public static class A implements IObject {
        @Override
        public void doIt() {
            System.out.println("OBJECTA");
        }
    }
    public static class B implements IObject {
        @Override
        public void doIt() {
            System.out.println("OBJECTB");
        }
    }

    public static void main(String[] args) {

        final boolean condition = true;

        IObject proxyObj =  (IObject)Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[]{IObject.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (condition)
                    new A().doIt();
                else
                    new B().doIt();
                return null;
             }
        });

        proxyObj.doIt();
    }
}

在这里,您正在为接口创建代理对象。 当您对此对象调用.doIt()时,调用处理程序将根据条件调用相应的实现。

然后可以传递代理并使用调用处理程序。

(应该清楚,这段代码仅给出一个概念,并且仅仅是如何使用代理接口/对象解决此问题的示例。)

答案 2 :(得分:1)

这实际上取决于您的用例。如果用例与您所描述的一样简单,则可以删除Consumer并直接在call函数中调用doIt。但是,我建议进一步推广该功能:

curl -X "PUT" http://your.url/demo/modify ...

然后通过以下方式调用它:

Path.DirectorySeparatorChar

以这种方式进行操作更干净,更扩展。它也需要相同数量的代码。 (未经测试,可能有错误,但是您知道了)。您可能会在纯(“纯”)函数式编程语言中看到这种方法,其中if语句只是一个带有条件的函数和两个函数(一个为true,一个为false)。

答案 3 :(得分:1)

使用 “工厂设计模式”

可以轻松实现上述要求

工厂设计模式涉及以下三个步骤:

  1. 为两种对象类型定义 通用接口
  2. 定义 实现公共接口的不同类
  3. 使用静态方法创建 Factory类 ,该方法将根据输入条件返回一种对象类型

这是一个有效的演示:

// File name: Demo.java

interface IObject {
    public void doIT();
}

class A implements IObject {
    public void doIT() {
        System.out.println("DoIT - Class A");
    }
}

class B implements IObject {
    public void doIT() {
        System.out.println("DoIT - Class B");
    }
}

class IObjectFactory {
    static IObject getObject(String CONDITION) {
        if(CONDITION.equalsIgnoreCase("CONDITION")) {
            return (new A());
        }
        return (new B());
    }
}

public class Demo {
    public static void main(String[] args) {
        IObject io1 = IObjectFactory.getObject("condition");
        IObject io2 = IObjectFactory.getObject("no condition");
        io1.doIT();
        io2.doIT();
    }
}

输出:

> javac Demo.java

> java Demo

DoIT - Class A
DoIT - Class B