Да, есть место и для абстрактных классов, и для интерфейсов.
Пойдем с конкретным примером. Мы рассмотрим, как сделать CheckingAccount
и SavingsAccount
из абстрактного AbstractBankAccount
и увидим, как мы можем использовать интерфейс, различающий два типа учетных записей.
Для начала вот абстрактный класс AbstractBankAccount
:
abstract class AbstractBankAccount
{
int balance;
public abstract void deposit(int amount);
public abstract void withdraw(int amount);
}
У нас есть баланс счета balance
и два метода deposit
и withdraw
, которые должны быть реализованы подклассами.
Как мы видим, абстрактный класс объявляет структуру того, как должны быть определены банковские счета. Как @Uri упоминает в своем ответе, в этом абстрактном классе есть состояние , то есть поле balance
. Это было бы невозможно с интерфейсом.
Теперь давайте подкласс AbstractBankAccount
, чтобы сделать CheckingAccount
class CheckingAccount extends AbstractBankAccount
{
public void deposit(int amount)
{
balance += amount;
}
public void withdraw(int amount)
{
balance -= amount;
}
}
В этом подклассе CheckingAccount
мы реализовали два абстрактных класса - здесь ничего интересного.
Теперь, как мы можем реализовать SavingsAccount
? Он отличается от CheckingAccount
тем, что будет вызывать интерес. Проценты могут быть увеличены с помощью метода deposit
, но, опять же, клиент не вносит проценты на депозит. Следовательно, было бы более понятным, если бы у нас был другой способ добавления денег на счет, в частности, для процентов, скажем, метод accrueInterest
.
Мы могли бы напрямую реализовать метод в SavingsAccount
, но у нас может быть больше типов банковских счетов, которые могут начислять проценты в будущем, поэтому мы можем захотеть создать интерфейс InterestBearing
, который имеет метод accrueInterest
:
interface InterestBearing
{
public void accrueInterest(int amount);
}
Итак, теперь мы можем создать класс SavingsAccount
, который может получить интерес благодаря реализации интерфейса InterestBearing
:
class SavingsAccount extends AbstractBankAccount implements InterestBearing
{
public void deposit(int amount)
{
balance += amount;
}
public void withdraw(int amount)
{
balance -= amount;
}
public void accrueInterest(int amount)
{
balance += amount;
}
}
Теперь, если мы хотим создать учетную запись другого типа, скажем, PremiumSavingsAccount
, мы можем создать подкласс AbstractBankAccount
и реализовать интерфейс InterestBearing
, чтобы создать другую учетную запись с процентами.
Интерфейс InterestBearing
можно увидеть как , добавляющий общую функцию к различным классам. Не имело бы смысла иметь возможность работать с процентами по текущему счету, когда на них не начисляются проценты.
Таким образом, действительно есть места, где абстрактные классы и интерфейсы могут сосуществовать и работать вместе в одной ситуации.