Две последние буквы SOLID для вас (
https://en.wikipedia.org/wiki/SOLID_(object-orient... ). Вообще рекомендую прочитать всю эту статью, она очень дельная (+ все ссылки из секции Design and development principles). Использование этих принципов позволят писать относительно неплохой код даже без понимания (которое приходит с опытом обычно). Кстати, в этих статьях должны быть ссылки на книги по ОО-проектированию (ну в любом случае они неплохо гуглятся).
Необходимость в интерфейсах и абстрактных классах возникает в основном в больших коммерческих проектах. Использование интерфейсов позволяет понизить связанность компонентов системы (их уровень знания друг о друге), что, в свою очередь, позволяет легче модифицировать систему, работая в команде. Например пишет один программист какой-то класс для запуска задач и делает у него метод, который принимает интерфейс IRunnable (возможно с одним методом run()) и описывает контракт (правила, как метод run() должен себя вести). После этого, любому другому программисту достаточно будет реализовать интерфейс по контракту и он сможет пользоваться классом для запуска задач. При этом, класс для запуска задач вообще понятия не имеет о том что он запускает, ему важно знать, что это можно запустить, и любому другому классу нет необходимости знать, как его запускают, достаточно просто реализовать метод.