メソッドが例外をスローする可能性があることを宣言できるJavaのような言語であっても、インターフェースを介して例外をスローするように実装に要求する方法はありません。
例外がスローされることを確実にする方法があります(絶対ではありませんがある程度)。インターフェースの抽象的な実装を作成できます。次に、GetUser
メソッドを抽象クラスのfinalとして実装し、戦略パターンを使用して、サブクラスの別の保護されたメンバーを呼び出し、有効なユーザー(nullなど)以外のものを返す場合は例外をスローします。これは、たとえば、他の開発者がnullオブジェクト型を返した場合でも落ちる可能性がありますUser
が、実際にここで意図を覆すために作業する必要があります。また、単にインターフェースを再実装することもできますが、これも悪いので、インターフェースを完全に抽象クラスに置き換えることを検討してください。
(同様の結果は、ラッピングデコレーターのようなものでサブクラス化する代わりに、委譲を使用して達成できます。)
別のオプションは、すべての実装コードが含まれるために渡す必要がある適合性テストスイートを作成することです。これがどの程度効果的であるかは、他のコードとのリンクをどの程度制御できるかに依存します。
また、このような要件が想定されているが、コードに完全に適用することができない場合は、明確なドキュメントとコミュニケーションが与えられることにも同意します。
コード例:
サブクラスメソッド:
public abstract class ExceptionalUserRepository : IUserRepository
{
public sealed User GetUser(int user_id)
{
User u = FindUserByID(user_id);
if(u == null)
{
throw new UserNotFoundException();
}
return u;
}
// subclasses implement this method instead
protected abstract User FindUserByID(int user_id);
// More code here
}
デコレータメソッド:
public sealed class DecoratedUserRepository : IUserRepository
{
private readonly IUserRepository _userRepository;
public DecoratedUserRepository(IUserRepository userRepository)
{
_userRepository = userRepository;
}
public User GetUser(int user_id)
{
User u = _userRepository.GetUser(user_id);
if(u == null)
{
throw new UserNotFoundException();
}
return u;
}
// More code here
}
public class SomeClass
{
private readonly IUserRepository _userRepository;
// They now *have* to pass in exactly what you want
public SomeClass(DecoratedUserRepository userRepository)
{
_userRepository = userRepository;
}
// More code
}
私が以前忘れていたことにしたい最後の要点は、これらのいずれかを実行すると、より具体的な実装に縛られることになります。つまり、実装開発者は、それほど自由度が低くなります。