Сегодня о последнем и очень важном принципе SOLID, инверсии зависимостей.
Определение принципа инверсии зависимостей из Википедии:
Модули высокого уровня не должны зависеть от модулей низкого уровня — отношения между ними должны быть результатом абстракции.
Другими словами, в классах и методах мы не должны использовать какие-либо имена конкретных классов, это должны быть только имена интерфейсов и абстрактных классов.
Кроме того, классы не должны наследовать от конкретных классов, а только от абстрактных классов и интерфейсов.
Что было бы, если бы высокоуровневые модули зависели от низкоуровневых?
Если, например, мы изменили что-то в классе, после которого наследуется другой класс, то эти изменения могли что-то выкинуть в наследующемся от него классе, поэтому использовать классы, зависящие от низкоуровневых модулей, было бы очень сложно, потому что, когда мы что-то меняем в этого класса нам, вероятно, придется что-то изменить в классе, после которого она наследуется.
Однако, если мы реверсируем эту зависимость, повторно использовать такие классы будет очень просто.
Посмотрим, как это выглядит на практике:
public void Pay(PayPal paypal) { //..... }
Это пример метода, который реализует оплату PayPal, вы не можете написать что-то подобное, приведенный выше пример теперь зависит от класса PayPal
Это должно выглядеть так:
public void Pay(IPayPal paypal) { //..... }
Теперь наш пример зависит от абстракции, т.е. от интерфейса IPayPal, теперь нам все равно, что происходит в низкоуровневых модулях, т.е. в предыдущем примере в PayPal > класс. Метод Pay просто реализует интерфейс IPayPal.
Это дает более или менее то, что мы можем изменить методы интерфейса IPayPal.
Такой подход также позволяет очень легко получить другие классы в некоторые библиотеки и использовать их в других проектах, если бы мы не использовали этот подход, нам пришлось бы перетаскивать все используемые нами классы или массу ссылок.
Давайте сделаем другой пример:
class Program { static void Main(string[] args) { var bank= new Bank(); } } public class Bank { ... public Bank() { _pay=new Pay(); } ... } public class Pay { public void PayCard() { //pay with the card } public void PayPal() { //pay via PayPal } }
В данном примере мы не имеем никакого влияния на то какие платежи будем использовать, высокоуровневый модуль это банк, а низкоуровневые платежи, в конструкторе сохраняется какие платежи мы будем использовать.
Как этот пример должен хорошо выглядеть? Более менее:
class Program { static void Main(string[] args) { var pay= new Pay(); var bank= new Bank(pay); } } public class Bank { ... public Bank(IPay pay) { _pay=pay } ... } interface IPay { void PayCard(); void PayPal(); } public class Pay,IPay { public void PayCard() { //pay with the card } public void PayPal() { //pay via PayPal } }
Теперь мы можем сами выбирать оплату, не углубляясь в низкоуровневые модули.
Резюме
Это все о принципе инверсии зависимостей.
Этот принцип связан с двумя очень важными паттернами, которые точно говорят вам, как избежать многоуровневых зависимостей и как облегчить написание многоуровневых зависимостей, из каких так называемых контейнеров эти паттерны включают внедрение зависимостей и инверсия управления. Оба описаны здесь.
Этот контент также можно найти в моем блоге https://steemit.com/solid/@slawas/solid-principles-5-dependency-inversion-principle
И в моем блоге devman: http://devman.pl/programtech/solid-principles-5-dependency-inversion-principle/
Стандартно напоминаю о бюллетене, в котором рассылаю уведомления о новых записях и дополнительную информацию о мире ИТ в целом.
И ОБЯЗАТЕЛЬНО присоединяйтесь к сообществу DevmanCommunity на фб, часть сообщества находится в одном месте
– сайт на фб: Devman.pl-Славомир Ковальски
— группа на фб: DevmanCommunity
Вы должны понять все незыблемые принципы сверху донизу, они вообще очень важны в программировании, благодаря им вы сможете вести большие проекты и делать их такими, чтобы их легко изменить, расширить, понять и т. д.
Спрашивайте, комментируйте в конце поста, делитесь им, оценивайте, делайте что хотите.