Loading...
mishomihaylov avatar mishomihaylov 67 Точки

Кога abstract class и кога Interface?

Здравейте! 
Имам трудности отностно разбирането кога да използвам абстрактен клас и кога интерфейс. Докато проверявах домашните(последните) на колеги видях, че някои са използвали интерфейси, а други абстрактни класове за едно и също. По дефиниция, до колкото разбрах, интерфейсите са договор, който показва, че дадения клас който наследява интерфейса е задължен да има съответната функционалност. От друга страна в домашната за наследяване и абстракция, в 3та задача имаме част от следното условие:


Extract interfaces for each class. (e.g. IPerson, IEmployee, IManager, etc.) The interfaces should hold their public properties and methods (e.g. IPerson should hold id, first name and last name). Each class should implement its respective interface.


Защо тук се изисква да сложим тези неща в интерфейс като може да ги бутнем в съответния клас или е сложено заради упражнение или правилно ли е винаги да вадим базова функционалност дори и от абстрактен клас в интерфейс? 
 

Благодаря!

1
C# OOP Basics
Filkolev avatar Filkolev 4482 Точки
Best Answer

Интерфейсите и абстрактните класове не са взаимозаменими. Това, че може да направиш абстрактен клас не значи, че не е нужно да направиш интерфейс. 

Интерфейсът е именно договор. Когато в дадено условие се каже, че имаш хора, които имат имена, имейли и възраст, това значи автоматично, че имаш договор - IPerson, в който имаш минимум гетъри за пропъртитата Name, Email, Age. Независимо как ще си направиш абстрактните или конкретни класове, които имплементират интерфейса, ти гарантираш, че всеки човек ще има тези три пропъртита. Когато пишеш приложение, по-скоро тръгни от интерфейсите, от нещата, които знаеш, че си длъжен да добавиш. Ако тръгнеш отдолу нагоре, какти се изрази "да извадиш в интерфейс базовата функционалност от класа", рискуваш да сложиш там функционалност, която всъщност не е базова. Примерно направил си метод, който върши нещо полезно в контекста на твоето приложение и решаваш, че това трябва да е публичен метод, съответно го добавяш и в интерфейса, за да може енджина да го ползва (приемаме, че енджина ти работи с IPerson). Потребителите на твоето приложение обаче може да не искат да ползват този метод; така замърсяваш IPerson с неща, които поначало не е било договорено, че са присъщи за един човек.

Абстрактният клас има имплементация (в общия случай). Там може да имаш логика по инициализиране, скрити сетъри с валидации, private/protected методи и т.н. Той служи за шаблон за конкретни класове, които да го наследят и да преизползват логиката в него. Но ако такава няма, не си длъжен да правиш абстрактен клас, може директно да имплементираш интерфейса в конкретни класове, стига да не повтаряш многократно един и същ код в тях.

В повечето случаи най-правилно е да имаш и интерфейс, и абстрактен клас, който го имплементира. Но да имаш само абстрактния клас прави приложението по-малко гъвкаво. В даден момент ще се наложи да обвържеш някакви класове с абстрактния клас, което е coupling. Затова за предпочитане е да имаш интерфейса независимо дали имаш или не абстрактен клас, така правиш dependency inversion, т.е. приложението ти ще разчита на интерфейси, на някаква базова гарантирана функционалност, а не на конкретни имплементации. Ако някой не харесва как си имплементирал абстрактния клас може да напише свой, който прави по-качествени валидации, или ползва по-ефикасни имплементации на някакви методи. Интерфейсите значат по-високо ниво на абстракция на приложението, което значи повече гъвкавост и свобода за този, който го ползва.

22
mishomihaylov avatar mishomihaylov 67 Точки

Ясно, благодаря за силния отговор! Но в такъв случай да разбирам ли, че по начина, по който имахме да правим задачата която съм описал по горе (интерфейс IPerson за клас Person и т.н.), е правилния начин за работа с интерфейси , макар и в случая да можеше да се направи и без тях? 

0
Filkolev avatar Filkolev 4482 Точки

Да, интерфейсите са инструмент за повишаване на абстракцията и правят приложението по-качествено от много гледни точки - разкаченост (класовете да зависят минимално от други класове), тестваемост, гъвкавост и др.

Когато в някой клас, да речем Manager, имаш списък от служители, които той ръководи, списъкът е правилно да е някаква колекция от IEmployee. Благодарение на полиморфизма това ще ти позволи в този списък да сложиш всякакви служители, дори такива, за които не подозираш, че в даден момент може да съществуват - примерно някой е взел кода ти и е решил, че му трябва някакъв вид служител, който има поведение на IEmployee, но пък не е точно Employee по начина, по който ти си го описал. Той си прави нов клас служители, които имплементират интерфейса, но не и твоя абстрактен клас или някой от наследниците му. Но приложението все още ще работи коректно, понеже няма проблем да имаш мениджъри, които ръководят новия тип служители - те не се интересуват от конкретния клас на служителите си, а само от това дали на абстрактно ниво те са някакъв вид служители (което значи да имплементират интерфейса директно или индиректно).

7
mishomihaylov avatar mishomihaylov 67 Точки

Разбирам, благодаря ти за изчерпателния отговор! 

0
Можем ли да използваме бисквитки?
Ние използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Можете да се съгласите с всички или част от тях.
Назад
Функционални
Използваме бисквитки и подобни технологии, за да предоставим нашите услуги. Използваме „сесийни“ бисквитки, за да Ви идентифицираме временно. Те се пазят само по време на активната употреба на услугите ни. След излизане от приложението, затваряне на браузъра или мобилното устройство, данните се трият. Използваме бисквитки, за да предоставим опцията „Запомни Ме“, която Ви позволява да използвате нашите услуги без да предоставяте потребителско име и парола. Допълнително е възможно да използваме бисквитки за да съхраняваме различни малки настройки, като избор на езика, позиции на менюта и персонализирано съдържание. Използваме бисквитки и за измерване на маркетинговите ни усилия.
Рекламни
Използваме бисквитки, за да измерваме маркетинг ефективността ни, броене на посещения, както и за проследяването дали дадено електронно писмо е било отворено.