Абстрактные классы полезны, когда вам нужен класс для наследования и полиморфизма, но нет смысла создавать экземпляр самого класса, только его подклассов. Они обычно используются, когда вы хотите определить шаблон для группы подклассов, которые совместно используют некоторый общий код реализации, но вы также хотите гарантировать, что объекты суперкласса не могут быть созданы.
Например, допустим, вам нужно создать объекты Dog, Cat, Hamster и Fish. Они обладают схожими свойствами, такими как цвет, размер и количество ног, а также поведение, поэтому вы создаете суперкласс Animal. Однако какого цвета это животное? Сколько ног у животного? В этом случае не имеет особого смысла создавать экземпляр объекта типа Animal, а только его подклассы.
Абстрактные классы также имеют дополнительное преимущество в полиморфизме - позволяя вам использовать (абстрактный) тип суперкласса в качестве аргумента метода или возвращаемого типа. Например, если у вас был класс PetOwner с методом train (), вы можете определить его как получение объекта типа Animal, например train (Animal a), в отличие от создания метода для каждого подтипа Animal.