個人的な見解ですが、インターフェースは"定義"のために利用します。たとえば製品情報を検索するサービスがあるとします。このサービスの利用者は製品情報がDBで管理されているのか、CSVファイルで管理されているのか、そういった具体的な実装については気にする必要はありません。利用者の関心はあくまで「製品IDを渡せば製品情報が取得できる」「すべての製品情報を取得できる」といったサービスのふるまい・定義にあります。
java
1public interface ProductSearchService {
2 Product find(String productId);
3 List<Product> findAll();
4}
5
6// 本番環境ではDBで製品情報を管理する。
7public DBProductService implements ProductService { ... };
8
9// テスト環境ではCSVで製品情報を管理する。
10public CSVProductService implements ProductService { ... };
一方、抽象クラスは"共通処理"のために利用します。製品情報を検索するクラス(ProductSearchService)とユーザ情報を検索するクラス(UserSearchService)があるとします。このふたつのクラスでは「DBにSELECT文を発行し結果を取得する」という処理が共通しています。この共通処理を抽象クラスに実装し、アクセス修飾子をprotectedとすることで、ProductSearchServiceとUserSearchService以外で利用させないようにします。
java
1public abstract class AbstractSearchService <T> {
2 protected List<T> executeSelectQuery(String query) { ... }
3}
4
5public class UserSearchService extends AbstractSearchService<User> {
6 public List<User> findAll() { }
7}
8
9public class ProductSearchService extends AbstractSearchService<Product> {
10 public List<Product> findAll() { }
11}
ただ、現代的なJavaプログラミングにおいては、抽象クラスはほとんど利用されなくなっているというのが個人的な感想です(インターフェースは利用されている)。共通処理のために抽象クラスを利用すると書きましたが、処理の共通化のために継承を利用することは推奨されません。そもそも現代的なオブジェクト指向プログラミングでは継承そのもの利用を避ける傾向にあります。これについてはJavaプログラミングにおいてもっとも有名なベストプラクティス集のひとつ『Effective Java 第3版』において次のような章がありますので、参考にしてみてください。
- 項目18 継承よりもコンポジションを選ぶ
- 項目19 継承のために設計および文書化する、でなければ継承を禁止する
- 項目20 抽象クラスよりもインタフェースを選ぶ
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。