Il motivo principale è che le interfacce ti consentono di fornire un terreno comune tra l'implementazione e chi utilizza il tuo codice. Ci sono scenari in cui non vuoi che il chiamante sappia come stai eseguendo determinate parti della logica. Le ragioni di ciò possono essere algoritmi di sicurezza o proprietari, per citarne alcuni.
Quando definisci un'interfaccia, definisci quali funzioni offri. Nella maggior parte dei casi, al chiamante non interessa come hai implementato, diciamo, un meccanismo di ordinamento. Il chiamante si preoccupa semplicemente che funzioni.
La codifica su un'interfaccia ti dà anche un grado relativamente grande di libertà dal momento che non sei in nessun punto costringendoti alla logica implementata. Pertanto, se il tuo metodo restituisce un List
anziché un ArrayList
, stai dando la libertà al chiamante di risolverlo in qualsiasi classe che implementi l'elenco.
Come ha detto @Benjamin Rogge, mi piacerebbe anche vedere dove leggi che le classi astratte sono più difficili da mantenere.