我当前正在思考一个应该在我的java程序中处理非法状态的概念。 我介绍了一个在图像上处理步骤的类。
public class ImageProcessor{
public Image processImage(Image img){
//do some processing steps
}
}
现在,我想介绍另一个应该在进行处理之前检查图像的类。
public class ImageChecker{
public void checkImage(Image img) throws ImageNotProcessableException{
//for example, if the image has a width of 0 the full process
//should be broken, throw an exception
if (img.width=0) throw new ImageNotProcessableException("width is 0");
//other conditions throwing also exceptions
// the image is fine, do nothing
}
}
这两个类应该在Coordinator类中使用。
public class Coordinator{
public void coordinate(Image img) throws ImageNotProcessableException{
//initialize both
imageChecker.checkImage(img); //if no exception is throw the process can run
imageprocessor.processImage(img);
}
}
现在的问题是,这种处理异常(为它们定义一个单独的方法)的方式是一种糟糕的编码风格吗?这种设计的想法是通过异常处理来防止污染处理代码。我希望协调员抛出异常,我认为这可能是一种有意义的方式。您怎么看?这是一个好方法还是反模式? 谢谢!
答案 0 :(得分:4)
验证方法本身是一个非常好的主意。您引入了非常好的关注点分离 - 在一个地方检查前提条件和验证,在另一个地方检查实际处理。
但是使用不正确。 ImageProcessor
应该热切地致电ImageChecker.checkImage()
。否则,您图书馆的客户可能会忘记调用它并传递无效图像。
另外* @ Damien_The_Unbeliever *提出了一个关于代码结构的非常好的观点。
为了使它尽可能花哨,我将创建一个带有两个实现的ImageProcessor
接口:一个执行实际处理,一个decorator实现(ImageChecker
)执行验证和传递已验证的对象以ImageProcessor
为目标。
通过这种方式,您可以使用安全或快速(假设验证成本高)实施。此外,您可能会在chain中引入其他元素,如缓存或分析。
答案 1 :(得分:1)
这并非不合理。虽然如果checkImage
存在的唯一目的是检查是否可以处理图像并且没有其他返回类型,那么让它返回状态代码/对象而不是抛出异常并返回void是合理的,例如,
ImageStatus status = checkImage(image);
if (status.isOk()) {
processImage(image);
}
这类似于检查除以零:
if (y != 0) {
z = x / y;
}
检查异常通常更适用于在尝试之前无法确定事先是否成功的情况,例如IOException。
答案 2 :(得分:1)
我在这里看到3个问题,将它们分开是有用的。
调用者应该看到一个名为“ImageProcessor”的类,还是一个名为“Coordinator”的类?
在主处理的单独方法中验证输入是否合适?
此代码是否应使用已检查的例外或未经检查的例外?
我的答案是:
为您公开的类或接口使用更漂亮的名称。所以,这里的“ImageProcessor”比“Coordinator”好得多。 (“协调员”听起来像是您不想公开的实施细节。)
这是一项实施决定。将一些验证逻辑分离成一个单独的方法,如果它使事情变得更清洁,那很好。但是,你需要小心陷入陷阱,认为可以预先考虑在后期处理过程中可能出错的所有事情。执行实际处理的方法仍然需要自由抛出异常,以便无论初始快速验证决定什么,它都可以尽可能准确地描述故障。此外,您希望避免在两个地方编写验证代码,因为这是不必要的代码重复。所以,我对这种分离持怀疑态度,但我需要看看代码。更有可能的是,最好将实际的图像处理本身分成各种子任务,并在需要时进行验证。
这是古老的Java检查异常辩论,在我们有生之年不会消失,在这里无法概括。但是,我认为共识已经相当强烈地转向支持使用运行时异常而不是检查异常。当然,遗留API仍然使用已检查的异常。但是对于大多数新代码来说,最好使用运行时异常而不是检查异常,因为这样可以提供更强大的代码。 (已检查的异常具有令人讨厌的属性,通常在它们到达异常处理程序之前被包装,重新包装,吞噬或以其他方式损坏,并且通过使每个人的throws子句变得更长,它们会导致大量的附带损害。)