Абстрактный класс определяет абстрактные методы. Любой класс, расширяющий другой класс, расширяет суперкласс, добавляя больше поведения. Если дочерний класс является абстрактным, он может добавить некоторое абстрактное поведение.
Абстрактные методы похожи на Контракты. Другой код может потреблять существующий код и может зависеть от него. Конкретный класс обязан следовать контракту, предоставляя реализацию.
Давайте рассмотрим пример ниже.
public abstract class SuperAbstract {
public void nonAbstract(){
// some code
}
public abstract void contract();
}
public abstract class SubAbstract extends SuperAbstract{
public void additionalNonAbstract()
// some code
}
public abstract void additionalContract();
}
public class Concrete extends SubAbstract{
public void contract(){
// implementation
}
public void additionalContract(){
//implementation
}
}
// although below is allowed and sometimes when we use an external library then this is one of the way but still this is not a good practice.
// dependencies should be on abstractions only and not on concrete implementation
public abstract class AnotherAbstract extends Concrete{
public void someMethod(){
//some code
}
public abstract void oneMoreContract();
}
public class ConcreteA extends AnotherAbstract{
public void oneMoreContract(){
//some implementation
}
}
Теперь обратите внимание, что всего мы определили 3 контракта, а ConcreteA
имеет все реализации. Также обратите внимание, что поскольку Concrete
предоставляет реализации для методов contract
и additionalContract
, следовательно, эти реализации наследуются ConcreteA
Код потребителя может легко зависеть от абстракции. Давайте посмотрим на это в коде пользователя (код потребителя)
public class Consumer{
public void m1(SuperAbstract c)
c.contract();
c.nonAbstract();
}
public void m2(AnotherAbstract c){
c.contract();
c.nonAbstract();
c.oneMoreContract();
c.additionalContract();
}
}
Теперь давайте посмотрим код подключения, обеспечивающий зависимости
public class Main{
public static void main(String[] args){
Consumer c = new Consumer();
c.m1(new Concrete());
c.m1(new ConcreteA());
c.m2(new ConcreteA());
}
}