让代码尝试不同的事情,直到成功为止
这是我第二次编写此类代码,并决定必须有一种更具可读性的方法来完成此任务:
我的代码试图找出一些东西,但定义不明确,或者有很多方法可以完成它。我希望我的代码能够尝试多种方法来解决这个问题,直到成功,或者耗尽策略。但我还没有找到一种方法来使其整洁且可读。
我的具体情况:我需要从接口中找到特定类型的方法。它可以被注释以明确,但它也可以是唯一合适的方法(根据其参数)。
因此,我的代码目前的读法如下:
Method candidateMethod = getMethodByAnnotation(clazz);
if (candidateMethod == null) {
candidateMethod = getMethodByBeingOnlyMethod(clazz);
}
if (candidateMethod == null) {
candidateMethod = getMethodByBeingOnlySuitableMethod(clazz);
}
if (candidateMethod == null) {
throw new NoSuitableMethodFoundException(clazz);
}
必须有更好的方法...
编辑:如果找到,这些方法将返回一个方法,否则null
。我可以将其切换为 try/catch 逻辑,但这很难使其更具可读性。
编辑2:不幸的是,我只能接受一个答案:(
This is the second time I found myself writing this kind of code, and decided that there must be a more readable way to accomplish this:
My code tries to figure something out, that's not exactly well defined, or there are many ways to accomplish it. I want my code to try out several ways to figure it out, until it succeeds, or it runs out of strategies. But I haven't found a way to make this neat and readable.
My particular case: I need to find a particular type of method from an interface. It can be annotated for explicitness, but it can also be the only suitable method around (per its arguments).
So, my code currently reads like so:
Method candidateMethod = getMethodByAnnotation(clazz);
if (candidateMethod == null) {
candidateMethod = getMethodByBeingOnlyMethod(clazz);
}
if (candidateMethod == null) {
candidateMethod = getMethodByBeingOnlySuitableMethod(clazz);
}
if (candidateMethod == null) {
throw new NoSuitableMethodFoundException(clazz);
}
There must be a better way…
Edit: The methods return a method if found, null
otherwise. I could switch that to try/catch logic, but that hardly makes it more readable.
Edit2: Unfortunately, I can accept only one answer :(
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
让您烦恼的是用于流程控制的重复模式——它应该让您烦恼——但在 Java 中对此没有太多处理方法。
我对重复的代码感到非常恼火。像这样的模式,所以对我来说,提取重复的副本和内容可能是值得的。粘贴控制代码并将其放入它自己的方法中:
这种方法的缺点是非常规并且可能更冗长,但优点是没有太多重复代码(更少的拼写错误)并且更容易阅读,因为代码中的混乱程度较少“肉”。
此外,一旦逻辑被提取到它自己的类中,冗长就根本不重要了,阅读/编辑很清晰,对我来说,这给出了(一旦你理解了 while 循环在做什么)
我确实有这个令人讨厌的愿望这样做:
突出显示实际正在执行的操作(按顺序),但在 Java 中这是完全不可接受的——您实际上会发现它在其他一些语言中很常见或更受欢迎。
附言。这在 groovy 中是非常优雅的(该死的,我讨厌这个词):
elvis 操作符规则。请注意,最后一行实际上可能不起作用,但如果不起作用,这将是一个微不足道的补丁。
What is bothering you is the repeating pattern used for flow control--and it should bother you--but there isn't too much to be done about it in Java.
I get really annoyed at repeated code & patterns like this, so for me it would probably be worth it to extract the repeated copy & paste control code and put it in it's own method:
Which has the disadvantage of being unconventional and possibly more verbose, but the advantage of not having as much repeated code (less typos) and reads easier because of there being a little less clutter in the "Meat".
Besides, once the logic has been extracted into it's own class, verbose doesn't matter at all, it's clarity for reading/editing and for me this gives that (once you understand what the while loop is doing)
I do have this nasty desire to do this:
To highlight what's actually being done (in order), but in Java this is completely unacceptable--you'd actually find it common or preferred in some other languages.
PS. This would be downright elegant (damn I hate that word) in groovy:
The elvis operator rules. Note, the last line may not actually work, but it would be a trivial patch if it doesn't.
我认为对于一小部分方法来说,你正在做的事情很好。
对于更大的集合,我可能倾向于构建一个责任链,它捕获了基本概念尝试一系列的事情直到其中一个成功。
I think for a small set of methods what you're doing is fine.
For a larger set, I might be inclined to build a Chain of Responsibility, which captures the base concept of trying a sequence of things until one works.
我不认为这是一个糟糕的做法。它有点冗长,但它清楚地传达了您正在做的事情,并且很容易更改。
不过,如果您想让它更简洁,您可以将方法
getMethod*
包装到实现接口(“IMethodFinder”)或类似接口的类中:然后您可以创建该类的实例,将将它们放入一个集合并对其进行循环:
虽然可以说有些复杂,但如果您需要在调用 findMethods* 方法之间做更多工作(例如更多验证该方法是否合适),或者如果查找方法的方法列表可以在运行时配置...
不过,您的方法可能也可以。
I don't think that this is such a bad way of doing it. It is a bit verbose, but it clearly conveys what you are doing, and is easy to change.
Still, if you want to make it more concise, you can wrap the methods
getMethod*
into a class which implements an interface ("IMethodFinder") or similar:Then you can create instances of you class, put them into a collection and loop over it:
While arguably somewhat more complicated, this will be easier to handle if you e.g. need to do more work between calling the findMethods* methods (such as more verification that the method is appropriate), or if the list of ways to find methods is configurable at runtime...
Still, your approach is probably OK as well.
我很遗憾地说,但你使用的方法似乎是被广泛接受的方法。我在 Spring、Maven 等大型库的代码库中看到了很多类似的代码。
但是,另一种选择是引入一个帮助器接口,它可以从给定的输入转换为给定的输出。像这样的东西:
和一个辅助方法
那么你就可以编写可重用的转换器来实现你的逻辑。每个转换器都必须实现 canConvert(input) 方法来决定是否使用其转换例程。
实际上:你的请求让我想起的是 Try.these(a,b,c) 方法。
您的案例的使用示例:
假设您有一些具有验证方法的 bean。有多种策略可以找到这些验证方法。首先,我们将检查该类型上是否存在此注释:
然后我们将检查是否存在名为“validate”的方法。为了让事情变得更容易,我假设所有方法都定义一个对象类型的参数。您可以选择不同的图案。无论如何,这是示例代码:
I'm sorry to say, but the method you use seems to be the widely accepted one. I see a lot of code like that in the code base of large libraries like Spring, Maven etc.
However, an alternative would be to introduce a helper interface that can convert from a given input to a given output. Something like this:
and a helper method
So then you could write reusable converters that implement your logic. Each of the converters would have to implement the
canConvert(input)
method to decide whether it's conversion routines will be used.Actually: what your request reminds me of is the Try.these(a,b,c) method in Prototype (Javascript).
Usage example for your case:
Let's say you have some beans that have validation methods. There are several strategies to find these validation methods. First we'll check whether this annotation is present on the type:
Then we'll check whether there's a method called "validate". To make things easier I assume, that all methods define a single parameter of type Object. You may choose a different pattern. Anyway, here's sample code:
您可以使用装饰器设计模式来完成查找某些内容的不同方式。
使用方法非常简单
You may use Decorator Design Pattern to accomplish different ways of finding out how to find something.
Usage is quite simple
更改 get... 方法的签名以便可以使用 try / catch 将是一个非常糟糕的主意。异常的代价是昂贵的,并且只能用于“异常”的情况。正如你所说,代码的可读性会较差。
Changing the signature of the get... methods so you can use try / catch would be a really bad idea. Exceptions are expensive and should only be used for "exceptional" conditions. And as you say, the code would be less readable.
对我来说,它是可读且可以理解的。我只是将代码中丑陋的部分提取到一个单独的方法中(遵循“Robert C.Martin:清洁代码”中的一些基本原则)并添加一些 javadoc(如有必要,请道歉),如下所示:
稍后在 <代码>MethodFinder.java
To me it is readable and understandable. I'd simply extract the ugly part of the code to a separate method (following some basic principles from "Robert C.Martin: Clean Code") and add some javadoc (and apologies, if necessary) like that:
and later on in
MethodFinder.java