Ще разгледаме няколко много важни принципа за ефективно проектиране на типове, които всеки добър софтуерен разработчик трябва да познава и прилага. Тези принципи не се отнасят само за езика C#, а са важни концепции при проектирането и изграждането на софтуер. Те намират приложение дори не само в софтуерното инженерство, но и във всички инженерни дисциплини като цяло.
Когато създаваме софтуерни системи целим да опростим работата по разработването, поддържането и развиването им. Това постигаме като се придържаме към ясна и разбираема структура на системата, близка до проблемната област, към която е ориентирана тази система. Добре направеният обектно-ориентиран дизайн намалява значително усилията за изучаване на системата при извършването на промени. За да го постигнем, е необходимо да се съобразяваме с няколко основни принципа, които ще разгледаме сега.
Функционална независимост (loose coupling)
Когато създаваме типове, които минимално зависят един от друг, можем да променяме всеки от тях без да е необходимо задълбочено познаване на цялата система. Към този принцип за функционална независимост трябва да се придържаме и когато дефинираме членовете на един тип. Ако минимизираме взаимозависимостите в системите, които разработваме, ще можем много по-лесно да използваме вече създадените модули, типове и методи в други проекти.
При проектирането на типове трябва да следваме принципа, че даден тип трябва да има ясна цел и да зависи минимално от останалите типове. Тази независимост улеснява поддръжка, опростява дизайна и позволява по-лесно преизползване на кода.
Трябва да се стремим типовете да издават възможно най-малко тайни за това как са имплементирани вътрешно. Потребителите на даден тип трябва да виждат като публични само свойствата и методите, които ги засягат, а останалите трябва да са скрити. Това намалява сложността на системата, защото намалява общия брой детайли, за които потребителят на даден тип трябва да мисли, когато иска да го използва. Скриването на имплементационните детайли (чрез капсулация) позволява промяната в имплементацията на даден тип без да се променя никой от типовете, който го използва.
Тъй като клас диаграмите показват връзките между типовете, те ни помагат да идентифицираме нивото на независимост между тях. Използвайки клас диаграми можем чисто визуално да преценим дали типовете, които използваме, имат прекалено много зависимости помежду си.
Силна логическа свързаност (strong cohesion)
Действията, които даден метод или клас извършва, трябва да бъдат логически свързани, да са насочени към решаването на една обща задача (не няколко логически несвързани задачи). Това свойство, е известно още като модулност. За да имаме ефективна модуларизация в проекта, който разработваме, трябва всички типове да предоставят ясен интерфейс, който е възможно най-прост и не съдържа излишни методи и свойства. Необходимо е още всички методи в типовете да са свързани логически и да имат имена, които ясно подсказват за какво служат. Не трябва да имаме типове, които имат няколко несвързани логически отговорности и изпълняват разнородни задачи. Това е признак на лош дизайн и води до много проблеми при поддръжката на системата.
Препоръчително е всеки тип, с който работим, както и всеки негов метод, да е свързан с решаването на обща задача и всяко действие, което се извършва да е стъпка или елемент от решаването й. Така системите които изграждаме, ще бъдат много по-разбираеми, и от там лесни за разширяване и поддръжка. Силната свързаност намалява сложността в проектите като спомага за ефективното разделяне на отговорностите в системата.
-
Формулирайте основните принципи на обектно-ориентираното програмиране. Дефинирайте понятията клас, обект, атрибут, метод, енкапсулация на данните, абстракция на данните и действията, наследяване, полиморфизъм.
-
Дефинирайте клас Student, който съдържа като private полета данните за един студент – трите имена, ЕГН, адрес (постоянен и временен), телефон (стационарен и мобилен), e-mail, курс, специалност, ВУЗ, факултет и т.н. Използвайте изброен тип (enumeration) за специалностите, ВУЗ-овете и факултетите. Дефинирайте свойства за достъп до полетата на класа.
-
Дефинирайте няколко конструктора за класа Student, които приемат различни параметри (пълните данни за студента или само част от тях). Неизвестните данни запълвайте с 0 или null.
-
Добавете в класа Student статично поле, което съдържа количеството инстанции, създадени от този клас от стартирането на програмата до момента. За целта променете по подходящ начин конструкторите на класа, така че да следят броя създадени инстанции.
-
Направете класа Student структура. Какви са разликите между клас и структура?
-
Направете нов клас StudentsTest, който има статичен метод за отпечатване на информацията за един или няколко студента. Методът трябва да приема променлив брой параметри.
-
Добавете към класа StudentsTest няколко статични полета от тип Student и статичен конструктор, който създава няколко инстанции на структурата Student с някакви примерни данни и ги записва в съответните статични полета.
-
Създайте интерфейс IAnimal, който моделира животните от реалния свят. Добавете към него метод Talk(), който отпечатва на конзолата специфичен за животното писък, булево свойство Predator, което връща дали животното е хищник и булев метод CouldEat(IAnimal), който връща дали животното се храни с посоченото друго животно. За проверка на типа животно използвайте оператора is.
-
Създайте класове, които имплементират интерфейса IAnimal и моделират животните "куче" и "жаба".
-
Създайте абстрактен клас Cat за животното "котка", който имплементира частично интерфейса IAnimal.
-
Създайте класове Kitten и Tomcat за животните "малко котенце" и "стар котарак", които наследяват абстрактния клас Cat и имплементират неговите абстрактни методи
-
Създайте клас CrazyCat, наследник на класа Tomcat за животното "луда котка", което издава кучешки звуци при извикване на виртуалния метод Talk().
-
Реализирайте клас със статичен метод, който инстанцира по един обект от всеки от класовете, поддържащи интерфейса IAnimal, и им извиква виртуалния метод Talk() през интерфейса IAnimal. Съответстват ли си животинските писъци на животните, които ги издават?
-
Направете всички полета на структурата Student с видимост private. Добавете дефиниции на свойства за четене и писане за всички полета.
-
Направете свойството за достъп до ЕГН полето от структурата Student само за четене. Направете и полето за ЕГН само за четене. Не забравяйте задължително да го инициализирате от всички конструктори на структурата.
-
Напишете клас, който представя комплексни числа и реализира основните операции с тях. Класът трябва да съдържа като private полета реална и имагинерна част за комплексното число и да предефинира операторите за събиране, изваждане, умножение и деление. Реализирайте виртуалния метод ToString() за улеснение при отпечатването на комплексни числа.
-
Реализирайте допълнителни оператори за имплицитно преобразуване на double в комплексно число и експлицитно преобразуване на комплексно число в double.
-
Добавете индексатор в класа за комплексни числа, който по индекс 0 връща реалната част, а по индекс 1 връща имагинерната част на дадено комплексно число.
-
Организирайте всички дефинирани типове в няколко пространства от имена.
-
Направете конструкторите на структурата Student да подава изключения при некоректно зададени данни за студент.
-
Добавете предизвикване на изключения в класа за комплексни числа, където е необходимо.
Сподели с приятели: |