0

编码时。尝试解决这个难题:

InputStreamDigestComputor 抛出 IOException 时如何设计类/方法?

由于模板方法抛出异常,但覆盖方法不抛出异常,我们似乎无法使用此设计结构。但是如果改变被覆盖的方法来抛出它,会导致其他子类都抛出它。那么对于这种情况有什么好的建议吗?

abstract class DigestComputor{


    String compute(DigestAlgorithm algorithm){
        MessageDigest instance;
        try {
            instance = MessageDigest.getInstance(algorithm.toString());
            updateMessageDigest(instance);

            return hex(instance.digest());
        } catch (NoSuchAlgorithmException e) {
            LOG.error(e.getMessage(), e);
            throw new UnsupportedOperationException(e.getMessage(), e);
        }
    }

    abstract void updateMessageDigest(MessageDigest instance);

}

class ByteBufferDigestComputor extends DigestComputor{

    private final ByteBuffer byteBuffer;

    public ByteBufferDigestComputor(ByteBuffer byteBuffer) {
        super();
        this.byteBuffer = byteBuffer;
    }

    @Override
    void updateMessageDigest(MessageDigest instance) {
        instance.update(byteBuffer);

    }

}

class InputStreamDigestComputor extends DigestComputor{


               // this place has error. due to exception. if I change the overrided method to throw it. evey caller will handle the exception. but 
    @Override
    void updateMessageDigest(MessageDigest instance) {
        throw new IOException();

    }

}
4

3 回答 3

2

在这种情况下,您的超类并不意味着抛出异常。

在这种情况下,您的子类因此会引发上层软件架构不期望的异常。因此,您可以:

  1. 更新所有子类以引发异常。

  2. 将整个 Digestor 类框架包装在一个新的类系统中。

  3. (最简单)维护当前代码并简单地将您希望抛出的任何异常包装在 RuntimeException 中。

RuntimeExceptions 是在 java 中抛出异常的惯用方式,编译器或方法签名未检查这些异常,这些异常发生有些意外。

于 2012-07-01T03:11:07.970 回答
1

正如其他人所建议的那样,最简单的做法是将真正的异常简单地包装在运行时异常中。因此,您不必在 throws 子句中声明异常。如果您有足够的野心,您可以创建自己的 RuntimeException 子类并在更高级别捕获它(这是 hibernate 所做的,它捕获所有抛出的 SQLExceptions 并将它们包装在 DataAccessException 的某个子类中,这是一个运行时异常)。

于 2012-07-01T03:29:12.010 回答
1

你的要求是精神分裂症。

您必须决定该DigestComputor.updateMessageDigest方法是否可以 throw IOException。如果您希望这成为可能,那么您必须将其添加到基类的签名中。这是强制调用者对IOException. 但缺点是您还强制其他子类的调用者处理IOException... 这不会发生。

您不能创建一个方法覆盖来引发被覆盖的方法没有的检查异常。这会破坏子类型的可替代性,而 Java 不允许这样做。

它就像一个岔路口。你必须决定走哪条路。你不能同时走两条路。


但是有一个妥协(有点):

public abstract class Base {
    public abstract void method() throws IOException;
}

public class A extends Base {
    public void method() throws IOException {
        //
    }
}

public class B extends Base {
    public void method() {  // Doesn't throw!!!
        //
    }
}

现在,如果调用者知道它有一个它的实例,B可以执行以下操作:

Base base = ...
B b = (B) base;
b.method();  // No need to catch or propagate IOException

(IIRC,这样做的能力......即减少在覆盖方法中抛出的异常......在Java 1.5中添加。)

于 2012-07-01T03:48:31.953 回答