Download presentation
Presentation is loading. Please wait.
1
Подготовка за Интервюта
Лекция 9: Design Patterns (Crash Course)
2
Второ Контролно Второто контролно за курса ще се проведе на 28-ми Май, от 18:00 часа за нечетни Ф.Н. и от 19:00 за четни Ф.Н. Реално самите тестове ще започнат в 18:15 и 19:15, но елате най-късно в, съответно, 18:10 и 19:10, за да не притеснявате останалите след като тестът е почнал Ще съдържа 25 въпроса за 50 минути Няма да има възможност да се прави на други дати Поради многото хора, които искаха да дойдат в другата група миналия път, този път това е официално разрешено – но всеки човек, решил да дойде с другата група, получава по 5 наказателни точки за това
3
Анкета за Финален Изпит
Мнозинството от вас искаха да направим финалния изпит преди сесията В момента тече втора анкета на коя дата точно да е изпитът ( Анкетата ще бъде спряна утре (15. Май) в 23:59, така че гласувайте, ако още не сте! Ще избера варианта с най-много гласове, за който мога да запазя достатъчно голяма зала На сайта на курса (fmi.informatika.bg) и във Facebook групата („Подготовка за Интервюта“) ще обявя точната дата, зала, и час веднага след като са известни
4
Финален Изпит Напомням какъв ще е форматът на финалния изпит:
Тест с 50 въпроса Продължителност от два астрономически часа Мнозинството въпроси ще са multiple choice (a/b/c/d/e) Всеки въпрос носи по 1 точка, грешни отговори не взимат точки Ще покрива целия материал от курса Ще ми отнеме известно време да ги проверя (много вероятно над седмица), така че не очаквайте да има резултати веднага
5
Игра Connect Напомням, че в момента тече втората игра за курса – Connect Можете да я достъпите тук: Поради забавяне с пускането на възможността за предаване, както и лека промяна в условието, срокът беше удължен до 23:59 на 3-ти Юни
6
CV-та за курса До края на Май ще връщам feedback и ще имате възможност за второ изпращане След това ще приемам CV-та до датата на изпита, но директно ще пиша точки, без обяснение какво не ми е харесало
7
Design Patterns Crash Course
8
Какво са ”Design Patterns”?
Начини за решаване на често-срещани проблеми при дизайн на софтуер Независими от програмния език – те са концепции за дизайн на кода, а не конкретни имплементации Може да считате, че са „best practices” за специфични проблеми Често, но не винаги, са свързани с ООП Някои от тях вече сте виждали, без да сте се замисляли за това Design Patterns можете да срещнете преведено на Български като „Шаблони за Дизайн“
9
Само няколко от много Тъй като това спокойно може (а и би трябвало!) да се вмести в отделен курс, ще минем много набързо само през няколко от тях Реално, обаче, има доста Хубав списък с кратки описания: Повече информация можете да намерите: В интернет (e.g. Wikipedia) В „Design Patterns: Elements of Reusable Object-Oriented Software” (Gamma, Helm, Johnson, Vlissides) Може да се намери лесно на pdf в Google Доста е скучна
10
Design Patterns на Интервюта
Обикновено питат кои петърни вие знаете и/или сте ползвали По тях лесно могат да разграничат Junior (който не се сеща за никакви) от Middle (който знае някои от основните) от Senior (който знае доста) Ако изброите някакви, но пропуснете основен, може да ви питат за него конкретно Дори да не знаете или да не се сещате, може да ви зададат такъв въпрос, че вие сами да стигнете до него (както ще направим в тази лекция)
11
Problem 1 Написали сте библиотека за различни функции, работещи върху набор от числа, които често ви се налага да ползвате: намиране на медиана, средно аритметично, рандом елемент, стандартно отклонение и др. Сега искате да направите библиотеката да работи върху произволни контейнери, които могат да съдържат числа, като например: Vector, Queue, Stack, HashSet, TreeSet, ArrayList, LinkedList… Какво бихте направили, за да не се налага да я модифицирате за всяка от тях, а и да има възможност за поддръжка на нови структури вбъдеще без промяна в кода й?
12
Pattern 1: Iterator Iterator е клас, който знае за вътрешното представяне на конкретен контейнер (например TreeSet), но го „скрива“ от потребителя, като предоставя стандартен интерфейс за обхождане на елементите В конкретната задача ще накарате потребителите на вашата библиотека да ѝ подават итератори на контейнерите, като така тя няма да се интересува от конкретната им имплементация Ако изникне нова структура (примерно TieredVector) можете да й напишете итератор и библиотеката ще работи без промяна и за нея Структурите данни, достъпни в C++ STL и в Java имат имплементирани итератори
13
Pattern 1: Пример template <typename Iterator> double getMean(Iterator it, Iterator end) { double sum = 0.0, cnt = 0.0; while (it != end) sum += *it++, cnt += 1.0; return cnt < 1 ? 0.0 : sum / cnt; }
14
Pattern 1: Пример void testIterators() { vector <int> vr; // ArrayList in Java set <int> ts; // TreeSet in Java unordered_set <int> hs; // HashSet in Java for (int num = ; num > 0; num--) { if (rand() % 3 == 0) { vr.push_back(num); ts.insert(num); hs.insert(num); } cout << "Vector: " << getMean(vr.begin(), vr.end()) << endl; cout << "TreeSet: " << getMean(ts.begin(), ts.end()) << endl; cout << "HashSet: " << getMean(hs.begin(), hs.end()) << endl;
15
Problem 2 Пишете ваша игра. Когато играчът започва дадено нейно ниво, трябва да бъдат заредени в паметта множество картинки (модели) и аудио файлове (звуци). Това зареждане потенциално може да отнеме доста време, в зависимост от големината на нивото, а някои от тях може да не бъдат ползвани изобщо (например ако играчът не обходи части от него). Как бихте подобрили user experience-а?
16
Pattern 2: Lazy Initialization
Ползва се най-вече в големи (тежки) програми и операционни системи, които ползват много памет и са съставени от много градивни частици (драйвери, картинки, звуци, фонтове, плъгини…)
17
Pattern 2: Lazy Initialization (when)
Lazy Initialization обаче може да има проблем с големи обекти (играта би „насякла“ докато се зареди) и би могъл да доведе до race condition, в случай, че няколко thread-а се опитат едновремено да инициализират все още неинициализиран обект
18
Problem 3 Искаме да напишем Python приложение, което от време на време прави прости заявки за уеб странци и обработва съдържанието им. Python има много пълна и гъвкава библиотека за целта – http. За съжаление, тя е толкова пълна и толкова гъвкава, че макар и да може да се ползва за на практика всичко, прости операции (които са ни нужни на нас, а и реално на мнозинството от потребителите) са направени учудващо сложно. Какво бихме направили?
19
Pattern 3: Facade Façade петърнът представлява симплификация на интерфейса на нещо, която покрива (и често значително опростява) неговите основни use case-и. Обикновено в замяна се жертва част от гъвкавостта на оригиналния интерфейс Примерът с Python е решен чрез библиотеката Requests, която е далеч по-user-friendly и работи върху вградената http. jQuery в някои отношения също може да се счита като фасада над стандартния JavaScript Понякога може да обединява API-то над няколко различни библиотеки (например Requests включва и urllib3, комбинирайки силата и на двете)
20
Problem 4 Написали сте софтуер, който клиентите на фирмата ви ползват. Тествайки при вас (с performance и load тестове), софтуерът работи много бързо, но няколко пъти на месец получавате оплаквания от клиенти, че при дадено пускане е вървял с пъти по-бавно от очакваното. За да дебъгнете проблема, вие искате да запишете колко време е работила всяка от функциите и следващия път, когато това се случи, да поискате лога от клиента. Сега задачата ви е за всяка функция да стартирате таймер в началото й, да го спрете в края й, и да запишете резултата, заедно с името на функцията, в лог файл. Как бихте направили това с минимални промени в кода?
21
Pattern 4: Decorator Decorator петърнът е код, който „обгръща“ функция, като изпълнява някакви неща точно преди извикването й, и точно след излизането от нея. Обикновено се ползва за да промени параметрите на функцията (например да нормализира някои от аргументите й), или изходните данни (например да криптира изхода, да промени хедъра на HTTP response и др.) В дадената задача в декоратора ще стартираме таймер преди извикването на функцията, ще го спираме след излизането от нея и ще запишем в лога резултата. Тъй като не зависи от параметрите на функцията, можем да ползваме един и същ декоратор за всички функции Промяната в кода е да маркираме върху кои функции искаме да изпълним декоратора (в Java това става преди дефиницията на функцията, и, разбира се, кодът на самия декоратор
22
Pattern 4: Decorator (Example)
def function1(): stime = time.time() ... etime = time.time() logging.getLogger().info(...) def function3():
23
Pattern 4: Decorator (Example)
# This is a decorator def timed_method(method): def timed(*args, **kw): stime = time.time() result = method(*args, **kw) etime = time.time() logging.getLogger().info(...) return result return timed
24
Pattern 4: Decorator (Example)
@timed_method def function1(): ... def function2(): def function3():
25
Problem 5 В дадена задача ви се налага няколко thread-а да четат и пишат от един и същ масив с данни. От време на време се случва така, че един тред записва данни на дадена позиция, веднага след което друг тред презаписва отгоре друга информация, без да вземе предвид промените от първия тред. Какво ще направите, за да спрете това да се случва?
26
Pattern 5: Lock Lock петърнът (също наричан mutex (mutual exclusion)) е начин за избягване на race condition-и чрез спиране на достъпа до даден обект или памет, докато върху нея се извършва писане. Обикновено се реализира чрез флаг, който се вдига, когато някой почне да пише и сваля обратно, след като писането завърши. Ако друг thread се опита да достъпи обекта, докато флагът е вдигнат, той се блокира, докато флагът бъде свален. В нашия проблем просто ще вкараме lock при писането Този петърн намира приложение при конкурентен достъп до произволни обекти (не само в паметта) – например за файл, мрежа, и други
27
Problem 6 Имате специфична инстанция на клас, която е сложна за конфигуриране, обаче ви се налага да ползвате на много места в кода (например Logger). Не искате да я правите глобална, нито да участва като member във всичките ви класове, нито да я подмятате насам-натам като аргумент на функциите. Какво бихте направили?
28
Pattern 6: Singleton Singleton петърнът е идеята да ограничим максималния брой създадени обекти от даден клас до един. При опит за създаване на втори обект, вместо това да се случи, се връща вече създадения Предимствата пред глобална променлива са, че: Не добавя име на променлива в namespace-a Позволяват lazy allocation & initialization Singleton може да бъде удачен и за пазене на State (състояние на обект/програма) Понякога се счита за anti-pattern, тъй като често се ползва за неща, за които няма нужда да се ползва
29
Problem 7.1 Имате клас, който при изпълнението на определени свои методи пише в база данни. Искате да го ползвате в unit test-ове, но не искате при всяко тяхно изпълняване да се правят записи в Production базата. За целта сте създали fake база, която искате класът да ползва за unit test-овете. Не искате, обаче, навсякъде в кода да подавате на конструктора на класа useProdDB = true/false. Какво можете да направите?
30
Problem 7.2 Ползвате Map за брояч на стрингове. Намирате за неудобно това, че трябва първо да проверите дали даден ключ се съдържа в Map-а, и ако не се, да го инициализирате с нула, преди да увеличите брояча. Решили сте да направите фасада (façade) над интерфейса на Map, която позволява +=, -=, *=, … дори за (все още) несъществуващи ключове, ползвайки някаква дефолтна стойност. За да направите това, трябва някак да можете да създавате обекти от произволни класове, без вашата фасада да има знание за тяхното конструиране. Как можете да направите това?
31
Pattern 7: Factory Factory патернът е начин да създаваме обекти без да имаме специфично знание за тях (например знаем само базовия им клас, но не и специфични). Обикновено се имплементира чрез обект или функция, която на базата на вътрешна информация или конфигурация знае кой точно конструктор на кой точно клас да извика, създава обект, и го връща В първия пример можем да имаме функция, която чете environment variable дали е в тест или не, създава обект от класа, викайки конструктора с правилната инстанция на базата (PROD или TEST), и накрая го връща Във втория пример може нашата фасада да изиска от потребителя Factory за конструиране на дефолтни стойности
32
Problem 8 Имаме клас, чиито конструктор с времето е нараснал дотолкова, че вече има 10+ параметъра и десетки различни overload-и. Сега за пореден път се налага да добавим нов параметър, като трябва да копираме множество от overload-ите и да им добавим и този параметър. Проблемът е, че с всеки нов параметър комбинациите (а, съответно, и броят конструктори) експоненциално нарастват. Как можем да се справим с това?
33
Pattern 8: Builder Builder патернът е клас, който помага за конструирането на друг клас. При него стъпка по стъпка указваме всички неща, важни за конструирането на основния клас, като накрая извикваме метод (обикновено .build()), той създава и ни връща желания от нас обект Ако забеляахте, Builder петърнът е доста подобен на Factory. Основната разлика е, че докато Factory обикновено създава обекти от различни наследници на даден клас, Builder създава обекти от един и същ клас, просто конфигурирани по различен начин В дадения проблем, бихме направили един единствен конструктор на основния клас, като изнесем цялата логика по конструирането и комбинирането на аргументите в Builder класа. При добавянето на нов аргумент в класа се променя единствено логиката в Builder класа (и потенциално някакви member variable данни на основния клас)
34
Problem 9 Имате клас, който при създаването си прави огромно количество изчисления и инициализация, отнемащи значително време. Всички новосъздадени обекти обаче на практика са еднакви, за едно и също стартиране на програмата. Какво можете да направите, за да олекотите създаването на обектите?
35
Pattern 9: Prototype Prototype петърнът е идеята да създадем една инстанция на тежък за генериране обект, която копираме всеки път когато ни потрябва нова. Обикновено копирането е значително по-бързо от инициализацията (която може да изисква изчисления или трансфер на данни по мрежата). В случая директно следваме петърна – правим метод в класа, който „създава“ нов обект, чрез копиране вече изчислен статичен обект от класа
36
Problem 10 Решили сте да пренапишете отначало даден проект, състоящ се от три основни компонента. С пренаписването сте променили интерфейсите им на комуникация един с друг от RPC на REST. След пренаписването два от тях работят както се очаква, но в третия постоянно изникват проблеми. След два пъти отлагане на датата на пускане, шефът ви недвузначно е показал, че ще трябва да си търсите нова работа, ако не работи до последно-обявения срок. Какво можете да направите?
37
Pattern 10: Adapter Adapter петърнът е това да се направи код, чиято единствена задача е да конвертира един интерфейс към друг, за да позволи работата на два иначе несъвместими сървиса В нашата задача бихме направил адаптер от интерфейса (RPC) на неработещата част от проекта от стария код към интерфейсите на двете работещи части от новия (REST). Така можем да ползваме поне две/трети от новия код, като в последствие (след release-а) оправим и подменим и третата. Let me tell you a story about Windows Vista…
38
Следваща лекция На 21-ви Май Ще разгледаме още теоретични въпроси:
Бази данни Числа с плаваща запетая Ще довършим компютърните архитектури
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.