【问题标题】:Execute a function "before each" method of the same class in java在java中执行同一类的函数“在每个”方法之前
【发布时间】:2020-02-18 19:48:02
【问题描述】:

我在一个类中有几个方法需要将布尔值设置为 true 才能正确执行。

我可以在每个方法中编写if 语句,但是如果我或其他人想要添加另一种方法,则不方便。我或他可能会忘记支票。

在 java 中有没有办法在一个类中的其他方法之前执行一个方法(就像 JUnit 对 @BeforeEach 所做的那样)?

编辑:提出了许多非常有趣的技术/答案/概念。当我了解他们时,我会与他们联系。谢谢。

【问题讨论】:

  • 可能有点过头了:您可以创建一个抽象类或接口,使用默认方法检查布尔值,并在您的类中扩展该方法。
  • 研究面向方面的编程(特别是在建议之前)-stackoverflow.com/questions/31121513/…
  • @NikitaLebed 如果你真的想阻止方法在听起来像 OP 想要的条件下执行,你需要一个 Around 建议。
  • 类似问题并不总是有相同的最佳答案。这个布尔值是干什么用的?
  • @MattTimmermans 这个布尔值是一个标志,指示软件是否已正确接收并处理 HTTP 请求。

标签: java


【解决方案1】:

让我们创建一个方法turnBooleanTrue(),其中boolean 设置为true,以便正确执行该方法。

然后,您可以编写自己的 InvocationHandler 来拦截对您的对象的调用,然后反射性地(使用反射 API)首先调用 turnBooleanTrue() 方法,然后调用被调用的方法。

看起来像这样

public class MyClassInvocationHandler implements InvocationHandler {

    // initiate an instance of the class
    MyClass myClass = new MyClassImpl();

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        // look up turnBooleanTrue() method
        Method turnBooleanTrue = myClass.getClass().getMethod("turnBooleanTrue");

        // invoke the method
        turnBooleanTrue.invoke(...); // toggle the boolean

        // invoke the method to which the call was made
        // pass in instance of class
        Object returnObj = method.invoke(myClass, args);

        return returnObj;
}

编辑

添加了一些行来初始化MyClass 的对象。您需要一些东西来调用方法并维护状态。在上面的代码示例中将util 更改为myClass

【讨论】:

  • InvokationHandler 是一种可能性。另一个是 AspectJ。
  • method.invoke 中的util 是什么?
  • 我在我的用例中覆盖了调用(更改了一些代码以满足我的需要)。它没有在其他方法之前调用,我不明白它应该是什么。
  • @FlorianCastelain 你能分享一下你是如何调用代码的以及在哪个实例上调用的吗?您现在需要调用代理实例上的方法
【解决方案2】:

考虑到我的用例,使用 AOP 或其他概念有点矫枉过正。所以我基本上对每个功能都做了检查。

【讨论】:

    【解决方案3】:

    使用 AOP,这就是您需要的样子:

    // wraps around all methods in your class that have a boolean parameter
    @Around(value = "@target(*..YourClass) && args(yourBool)", argNames = "jp,yourBool")
    Object scheduleRequest(ProceedingJoinPoint jp, boolean yourBool) {
        if (yourBool) {
            jp.proceed(yourBool);
        } else {
            throw new RuntimeException("cannot execute this method!");
        }
    }
    

    这将处理该方法将您所说的需要评估的boolean 作为其(唯一)参数的情况。如果它来自不同的来源,您可能需要以某种方式将其连接到方面,这取决于您的整体设计。

    【讨论】:

      【解决方案4】:

      我建议一个简单的解决方案,将您的工作流程分为四个部分。

      您有一个用于执行命令的界面。
      您有一个界面来定义您可以使用哪些命令。
      您有一个包装器可以分析您的布尔值。
      你有一个工作执行类的实现,它实现了第二个接口。

      你的包装器初始化了worker。
      您的包装器公开了一个接受执行接口的操作执行命令。
      如果布尔值为真,则将工作人员传递给正在执行的接口工作方法。
      执行接口工作方法调用命令实例接口worker上的工作函数。

      在线查看:https://ideone.com/H6lQO8

      class Ideone
      {
          public static void main (String[] args) throws java.lang.Exception
          {
              WorkDistributer wd = new WorkDistributer();
              wd.enable();
              wd.performAction((w) -> {w.printHello();});
              wd.disable();
              wd.performAction((w) -> {w.printHello();});
              wd.enable();
              wd.performAction((w) -> {w.printAnswer();});
              wd.disable();
              wd.performAction((w) -> {w.printAnswer();});
          }
      }
      class WorkDistributer 
      {
          private boolean enabled = false;
          private ActionPerformer worker;
          public WorkDistributer() {
              this.worker = new Worker();
          }
          public void enable() {
             enabled = true;
          }
          public void disable() {
              enabled = false;
          }
          public void performAction(ActionCommand command) {
              if(this.enabled) {
                 command.run(this.worker);
              }
          }
      }
      class Worker implements ActionPerformer {
          public void printHello() {
              System.out.println("hello");
          }
          public void printAnswer() {
              System.out.println(21 * 2);
          }
      }
      
      interface ActionPerformer {
          public void printHello();
          public void printAnswer();
      }
      
      interface ActionCommand {
          public void run(ActionPerformer worker);
      }
      

      【讨论】:

      • 对于这种装饰器,我想说使用Runnable 作为命令就足够了,并且使用工厂方法创建的评估布尔值的单个包装器(static Runnable wrap(Runnable wrapped, Supplier<Boolean> allowed)) { return () -> { if (allowed.get()) wrapped.run(); })跨度>
      • @daniu 可以这样做,但这不是我喜欢的方式。对我来说,您提出的方法失去了代码流布局的很多“意图”和自我记录属性。但每个人都有自己喜欢的方法。它比依赖反射要好得多。使用本机方法来引导代码流在将来发生更改时强制执行正确的操作。 “魔法”反射方法可能会被遗忘,从而导致长时间的行为搜寻。
      猜你喜欢
      • 2016-09-28
      • 2015-12-06
      • 2015-12-01
      • 1970-01-01
      • 1970-01-01
      • 2017-05-10
      • 1970-01-01
      • 1970-01-01
      • 2011-10-22
      相关资源
      最近更新 更多