The primary downside is that you get indirect code - you can’t just follow the call into the implementation to see what it does - you must either understand the interface and what it promises to do or try to dynamically at runtime discover what code is actually called. This adds mental overhead to understanding the code. It’s less so if you’re well disciplined in defining the interfaces and contracts, but being well disciplined is not easy to do.
5 Likes