Java - 开发者实例化对象时自动添加方法调用

Java - Auto add method call when developer instantiates an object

我想知道开发人员是否可以编写 class 以便当其他开发人员实例化上述 class 的对象时,调用 class 的特定方法=59=] 被添加到他的代码中。

让我更具体一点。假设我创建了一个名为 A 的 class,其结构如下:

public class A {

    public A() {
        // Some instantiations
    }

    // Code class

    // Method that always should be added
    public void method() {
        // Code
    }
}

我将这个 class 包装到一个包中,其他一些开发人员在一个新对象中实例化 class A。当他这样做时,在实例化之后立即添加了对 method() 的调用,可能在其上方有一条评论:

// Code
A myA = new A();
// Do some operations on A

// You should always wrap up with a call on method
myA.method();

// Code

这只是为了通知开发人员不要忘记在他的代码中的特定位置调用它。

我问这个问题的原因是因为我创建了一个 class,其中包含一个将在大型项目以及未来项目中使用的排队机制。我需要强制每个未来的开发人员在他的代码末尾引用一个名为 close() 的方法,以终止与排队系统的连接。如果他忘记这样做(并且 he/she 这样做的可能性很高),连接将打开,给整个项目增加巨大的开销。

如果没有办法实现它(据我所知,我想不出任何东西),那么 Oracle 在标准 JDK 中不包含这样的东西背后的逻辑是什么?我可以想到可以从中受益的 JDK 自己的库的示例(例如,当您完成写入文件时关闭 PrintWriter),所以我不认为这是一个我这边对 Java 的原则有误解。

更新

因为我想我不小心点燃了火焰war...

我确实认为一个好的 API 是以这样的方式编写的 自动 。实例化一个 object/call 方法,其余的自动完成。但是对于我的情况,我需要像 C++ 的析构函数这样的东西:一种强制或以其他方式 warn 开发人员关闭与他创建的排队系统的连接的方法。

更新 2

不幸的是,该项目是用 JDK 7 编写的,不支持 lambda 函数。

更新 3

事实证明我的假设是正确的,并且没有可以利用的标准 Java 功能(除了 lambda 函数之外)。我可以在其他开发人员忘记关闭连接的 class 上至少添加一个 warning 吗?

你走错了路。意思是:好的API很容易被正确使用,很难被错误使用。

如果您希望 new A() 后跟一些 doSomething(),那么解决方案如下:

  • 将该构造函数设为私有
  • 将静态辅助方法放入 A 中执行

这个:

public static A makeA() {
   A result = new A();
   doSomething();
   return result;
}

或类似的东西。换句话说:不要争取复杂的、非标准的、看起来脏兮兮的变通办法。相反:让不可能做错事。

我所知道的 IDE 都没有这个功能,但大多数都有插件。你可以编写自己的插件来实现它。

其他选项是像这样重新设计您的 API

class Main {
    public static void main(String[] arg) {

        String res = QueueService.doWithQueue(q -> q.someMethod());

    }
}

class QueueService {
    public static <T> T doWithQueue(DoWithQueue<T> m) {
        MyQueue myQueue = new MyQueue();
        T t = m.method(myQueue);
        myQueue.close();
        return t;
    }
}

interface DoWithQueue<T> {
    T method(MyQueue m);
}

class MyQueue {
    public void close() {
    }

    public String someMethod() {
        return "something";
    }
}

并且不要让 MyQueue 以其他方式晒黑至 QueueService

您可能想要实现的是一种 "Use with" 模式,您只在 class 上公开一个 public 方法,它将接受 "Use strategy"对于您的对象,同时作为作者,您可以完全控制资源对象的实例化和销毁。

考虑此资源 class:

public class ExpensiveResource {
  private ExpensiveResource() {} // private so only we can get an instance

  public void destroy() { // a method we always want to call after we're done
    <...>
  }

  <...more operations with resource here...>

  // This is the only actual entry point where anyone can access instances of your resource.
  // As you can see, destroy() is always called no matter what.
  public static void use(UsageStrategy strategy) {
    ExpensiveResource resource = new ExpensiveResource();
    try {
      strategy.useResource(resource);
    }
    finally {
      resource.destroy();
    }
  }

  public static interface UsageStrategy extends Consumer<ExpensiveResource> {
    @Override
    default void accept(ExpensiveResource arg0) {
      useResource(arg0);
    }

    void useResource(ExpensiveResource resource);
  }
}

任何想要使用您的资源的人都需要这样调用它:

ExpensiveResource.use(resource -> {
  var a = resource.operation1();
  resource.operation2();
  resource.operation3(a);
  <... etc. ...>
});

如果您仍在使用 Java7,您需要做的就是创建一个匿名的 class:

ExpensiveResource.use(new UsageStrategy() {
  public void useResource(ExpensiveResource resource) {
    resource.operation1();
    <... etc. ...>
  }
});

由于样板语法,它远没有那么优雅,但基本思想是一样的,升级后即可开始享受 Java8 的好处。

(注意 我从上面的 java.util.function.Consumer 扩展了 UsageStrategy。Java 7 不会有这个 class,但你可以删除extendsdefault 一种方法)。

您应该利用 Java7 中引入的 try-with-resouce 功能。

您前面提到的 class A 应该实现接口 AutoClosable 然后:

public class A implements AutoClosable {
    public void close() {
        // Do closing
    }
}

使用 A 的实例应该发生在 try-with 资源块中:

try(A a = new A()) {
    // Do something
}

这确保了 close 方法在到达 try 块的末尾后被调用。

最后,至少 eclipse 编译器可以将忘记在 try-with-resource 块中使用 A 标记为错误。