След като един клас е написан и изпробван тойще представлява (в идеалния случай) полезно късче код. Това изважда наяве че написването на класа изисква опит и познаване на въпроса каквито не всеки има. Веднъж направили го обаче, то плаче да бъде използувано повторно. Повторното използуване на код е най-мощния лост, който ООП предоставя.
Най-простия начин за повторно използуване на код е прякото използуване на обекта, но също може този обект да се постави в друг обект. Наричаме това "създаване на член-обект". Новият клас може да се дъздаде от каквито и да са типове обекти, толкова, колкото са необходими за да се получи необходимото поведение. Тази концепция е наречена композиция, доколкото се композира нов клас от съществуващи класове. Понякога това се нарича “има” зависимост, както в “колата има багажник”.
Композицията дава мтого гъвкавост. Член-обектиге в новия клас са обикновено private и това не дава възможност да се използуват направо от потребителя. Това дава възможност да бъдат променяни без да се променя клиентския код. Може да променяте също много обекти по време на изпълнение, което дава голяма гъвкавост. Наследяването, което ще се опише малко по-късно, не дава такава гъвкавост, понеже има ограничения въху класовете.
Понеже наследяването е толкова важно за ООП може да се създаде впечатление, че то трябва да се използува навсякъде. Това може да доведе до тромав и излишно сложен дизайн. Вместо това трябва да се търси първо композицията, понеже е по-проста и гъвкава. Ако се възприеме този подход, дизайнът ще стои по-чист. Трябва да има очевидна причина за да се използва наследяването.
Наследяване:
повторно използване на интерфейса
Самата концепция за обекте удобен инструмент. Тя позволява да се пакетират данни и код според концепция, така че може да представите идеята с езика на проблемното пространство, а не с идиомите на подлежащата машина. Тези концепции са изразени в първичната идея за даннов тип (използвайки ключовата дума class).
Би било жалко, обаче, да се създаде някакъв тип и после да трябва да се създава нов с подобна функционалност. Би било по-добре ако може да вземем съществуващ тип, да го клонираме и да придадем нужните свойства на клонинга. Това е, което фактически се получава с наследяването, с това изключение, че оригиналният клас (наречен базов или супер или родителски клас) е променен, промененият “клонинг” (наречен извлечен или извлечен или под- или дъщерен клас) също отразява помените. Наследяването се прилага в Java с ключовата дума extends. Когато правите нов клас казвате че той extends съществуващ клас.
Чрез извличане се създава нов тип, който не само всички членове на наследения клас (макар и тези които са private да са скрити и недостъпни), но - което е по-важно - повтаря интерфейса на базовия клас. Това значи, че всички съобщения, които се разбират от базовия клас се разбират и от извлечения. Тъй като типа на класа е известен от съобщенията, които той разбира, извлечения клас е от същия тип като базовия клас. Тази еквивалентност на типовете чрез интерфейсите им е главния вход към разбирането на ООП.
Тъй като базовия и извлечения клас имат един и същ интерфейс, трябва да има някакъв код, който се изпълнява с интерфейса. Ще рече, трябва да има метод който се изпълнява при приемането на дадено съобщение. Ако просто наследите клас без нищо друго да пишете, методите на базовия клас директно минават и в наследения. Тоест извлеченият обект има не само същия тип, но и същото поведение, което не изглежда особено интересно.
Има два пътя да направите извлечения клас различен от този, който се наследява. Първият е много праволинеен: просто пишете нови функции в новия клас. Тези нови функции не са част от интерфейса на базовия клас. Значи ако базовият клас не прави всичко, което искате, просто добавяте необходимото в новия клас. Тази примитивна употреба за интерфейс понякога е най-добрия начин да се реши проблем. Трябва да се погледне, обаче, по-отблизо възможността базовия клас да се нуждае от тези функции.
Въпраки че extends предполага, че ще се добавят нови функции, това не е непременно вярно. Другия начин да се направи втория клас различен е да се промени поведението на съществуваща функция на базовия клас. Това се означава с подтискане на функцията.
За да се подтисне функцията просто се дава нова дефиниция за нея в новия клас. Казваме: “Използвам същата интерфейсна функция, но искам да прави нещо различно.”
Отношенията "е" и "прилича на"
Може да възникне известен дебат относно интерфейса: наследяването да подтиска ли само функциите на базовия клас? Това значи че извлеченият тип е точно същия като на базовия клас, защото има същия интерфейс. Като резултат обект от единия клас може да замести обект от другия клас. Това може да се нарече чиста субституция. По усещане това е идеалният начин да се третира наследяването. Често се казва че отношението между базовия клас и извлечения клас в този случай е е, понеже може да се каже “кръгът е фигура.” Пробата за уместност на наследяването е дали може да се прокара е отношение между двата класа и да му се придаде смисъл.
Има случаи, когато се налага да се добави интерфейс в извлечения тип и по този начин да се получи нов тип. Новият тип все още може да замества базовия, но работата не изглежда наред, защото стария тип не може да използва новите функции. Това може да се опише като отношение е подобен на; новия тип има интерфейса на стария, но има и нови функции и не може да се каже, че е точно същия. Например един климатик. Да допуснем, че в къщи всичко е нагласено да се управлява охлаждането, т.е. има интерфейс на охлаждането. Да допуснем че климатикът се е развалил и сте го заменили с топлинна помпа, която може да топли и охлажда. Помпата е подобна на климатика, но може повече. Понеже е прокарано управление само за охлаждането, може да се управлява само тази част на новия обект. Интерфейсът на новия обект е бил разширен и системата не знае за това.
Като се погледне принципа на субституцията лесно може да се помисли, че това е единствения начин да се свърши работата и е добре, ако програмата ви ги върши то него. Ще се случи обаче да изглежда също толкова необходимо да се добавят нови функции . С проверка и двата случая трябва да станат приемливо очевидни.
Сподели с приятели: |