Интерфейс - это контракт, который реализовывает класс, а пользователи класса знают как этот класс использовать. Это альтернатива множественному наследованию. Например у вас есть два типа коллекции: бинарное дерево и граф. Это довольно отличающиеся структуры данных. Но каждая из коллекций может реализовать интерфейс Iterator и в этом случае интерпретатор будет знать как перебрать коллекцию в цикле foreach.
Абстрактные классы в основном используются в том случае, если какую-то часть кода можно описать в родительском классе, но для того чтоб эта часть приобрела смысл, нужна конкретика: дополнить общую картину подробностями в виде методов или полей. Если вы присмотритесь к абстрактным классам в современных фреймворках, то увидите что сам по себе абстрактный класс не имеет смысла. Например, если создать объект такого класса оператором new, то этому объекту всё равно будет чего-то не хватать и именно это что-то и добавляют дочерние классы.