В рамките на 5 седмици ще ви представим поредица от 5 статии, предназначена за програмисти, които искат да повишат нивото на качество в работата си. Следващите принципи, са само началото на поредица от различни добри практики и насоки, формулирани от едни от най-опитните в бранша. Голяма част от тях са описани в детайли в книгата на Робърт Мартин – “Agile Principles, Patterns, and Practices in C#”. Петте принципа в тези статии засягат ежедневните предизвикателства, пред които е изправен всеки един програмист и като такъв е добре, да е запознат с правилните начини за справянето с тях. Спазването на всеки един от принципите, е признак на професионализъм, и ще доведе до по-добър дизайн на дадена система. Това е част 4-та от поредицата от петте статии.
Част I-ва прочетете тук: SOLID принципи за обектно ориентиран софтуерен дизайн – Част I
Част II-ра прочетете тук: SOLID принципи за обектно ориентиран софтуерен дизайн – Част II
Част III-та прочетете тук: SOLID принципи за обектно ориентиран софтуерен дизайн – Част III
Част IV-та прочетете тук: SOLID принципи за обектно ориентиран софтуерен дизайн – Част IV
The Dependency-Inversion Principle (DIP)
“Модулите на високо ниво, не трябва да зависят от модули на ниско ниво.”
Според Грейди Буч всички добре структурирани обектно-ориентирани архитектури имат ясно дефинирани слоеве. Тези слоеве са изградени от така наречените модули от високо и модули от ниско ниво. Под модули се има предвид група от класове, които работят заедно. Всички модули, които съдържат важните правила (политики) за бизнеса в дадено приложение, се наричат от високо ниво. Тези модули съдържат смисъла на приложението. Всички модули, които съдържат подробностите за изпълнението на дадена политика, се наричат модули от ниско ниво. Когато модули от високо ниво зависят от модулите от по-ниско ниво, промените в модулите от по-ниско ниво могат да имат директен ефект върху модулите от по-високо ниво. Това затруднява поддръжката на приложението. За да се избегне това само модулите от високо ниво трябва да оказват влияние върху подробните модули на ниско ниво, не и обратното. Модулите, които съдържат бизнес правила на високо ниво трябва да имат предимство пред модулите, които съдържат подробностите за изпълнението. Модулите на високо ниво трябва да бъдат лесни за преизползване. Нека го покажем на практика.
Да вземем за пример приложение, в което искаме да управляваме състоянието на лампа чрез бутон. Този бутон ще се връща в първоначално състояние когато бъде отпуснат. За по-улеснено представяне на модела ще приемем, че бутонът отчита събитието натискане и събитието отпускане. Примерна имплементация на това задание може да е следната:
При така описаните класове, най-лесният начин да накараме бутона да управлява лампата е като в самия него запазим инстанция на обекта лампа, който той ще управлява. По този начин метода за управление на състоянията на лампата става тривиален.
Това обаче означава, че класът бутон ще бъде засегнат от бъдещи промени в класа лампа. Освен това, няма да е възможно повторното използване на класа бутон за управление на обект мотор например. В този модел обектите от тип бутон могат да контролират само обекти на лампа. Това решение нарушава Dependency-Inversion Principle. Политиката на високо ниво на приложението не е отделена от детайлите на ниско ниво. Абстракциите не са отделени от подробностите. Без такова разделяне политиката на високо ниво автоматично зависи от подробностите на ниско ниво.
Решението на този проблем е въвеждането на ново ниво на абстракция.
Възможен подход е добавянето на следния интерфейс:
Чрез него разделяме, какво действие се извършва от това как се извършва то. За да въведем в употреба този интерфейс са необходими няколко промени по текущата имплементация. След реализирането им крайното решение може да изглежда ето така:
Оттук възможностите за разширяване на функционалността са отворени. Ако се наложи да добавим новият обект мотор, всичко което трябва да направим е просто в неговият клас да имплементираме вече изнесения интерфейс.
Също така, ако се наложи да добавим нов вид бутон, който да остава постоянно натиснат или постоянно изключен отново може да използваме интерфейса. По този начин новия бутон има възможност да управлява всички видове обекти, който импелемнтират интерфейса:
В традиционното процедурно програмиране винаги се създава зависима структура, в която всичко зависи от подробностите. Това е голям проблем, тъй като често се налагат промени в някои от детайлите. Обектно-ориентираното програмиране дава възможност за обръщане на посоката на зависимост така, че детайлите да зависят от абстракция. Всъщност тази инверсия на зависимостите е основен белег на добрия обектно-ориентиран дизайн. Няма значение на какъв език е написана програмата. Ако нейните зависимости са обърнати, тя ще има добър дизайн. Ако нейните зависимости не са обърнати, тя ще има процедурен дизайн. Dependency-Inversion Principle е основният механизъм, с който се постига обръщане на посоката на зависимост. Правилното му приложение е необходимо за създаването на код, който може да бъде употребяван многократно. Когато абстракциите и детайлите са изолирани едни от други, кодът става много по-лесен за поддръжка.
В заключение на тази статия, можем да отбележим, че създаването на качествен продукт, пряко зависи от писането на качествен код. Тези принципи ясно и точно дефинират стандартни подходи към вече добре познати проблеми. Ако вземем първите букви на всички тези принципи се образува съкращението SOLID. Прилагайки ги, всяко приложение ще има “твърда” основа, върху която може лесно да се гради. Това трябва да е главната цел при изграждането на едно приложение.
SOLID принципите са само част от добрите практики, прилагани от водещите професионалисти в сферата на програмирането. Други такива са принципите DRY, KISS, YAGNI, GRASP и др.
Допълнителни материали:
Agile Principles, Patterns, and Practices in C#: http://a.co/2BXHOC4
https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
https://en.wikipedia.org/wiki/KISS_principle
https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it
https://en.wikipedia.org/wiki/GRASP_(object-oriented_design)
За автора: Костадин Капсъзов
– Костадин Капсъзов се занимава професионално с програмиране от 2012 година.
– Работил е за над 10 различни български и международни компании, като трупа опит и знания в различни сфери на бизнеса.
– Успешно участва в над 13 проекта, използващи различни програмни езици като: C#, C++, Java, Python, JavaScript, Objective-C и др.
– В момента е програмист в екипа „Нови разработки и Иновации“ на българската технологична компания UltraPlay.
– От 2014 г. Започва активно да се интересува от „Software Craftsmanship“ – подход за разработка на софтуер, който набляга на качеството на програмните уменията на софтуерните разработчици. Около този подход се основава гилдия, която споделя идеите, описани от Анди Хънт, в книгата „The Pragmatic Programmer“ и книгата на Дейв Томас „Software Craftsmanship“. Тези идеи описват разработката на софтуер като занаят, подобен на занаятите практикувани от занаятчийските гилдии през Средновековековието.
Стани част от потребителските групи на DEV.BG. Виж всички потребителски групи и избери най-интересните за теб.
Визия: Личен архив
Прочети още:
6 от най-популярните Machine Learning алгоритми – приложения и възможности
Какво означава една система да е „reactive“? Основна концепция на Reactive programming