Komponentowe i rozproszone Jak pisać dobry kod. ZŁY KOD WYGLĄDA TAK...

Slides:



Advertisements
Podobne prezentacje
C++ wykład 2 ( ) Klasy i obiekty.
Advertisements

C++ wykład 4 ( ) Przeciążanie operatorów.
Klasy abstrakcyjne i interfejsy
1 Dzisiejszy wykład Wzorce funkcji Wzorce klas. 2 Wzorce Często pojawia się konieczność pisania podobnych funkcji lub klas operujących na argumentach.
1 Dzisiejszy wykład Wzorce funkcji Wzorce klas Tablica asocjacyjna Składowe statyczne.
Wzorce.
Dziedziczenie. Po co nam dziedziczenie? class osoba { char * imie, char * imie, * nazwisko; * nazwisko;public: void wypisz_imie(); void wypisz_imie();
Obiektowe metody projektowania systemów Design Patterns STRATEGY.
Bezpieczeństwo wyjątków w C++: OpenGL
Kamil Łącki Dominik Strzelichowski
Szablony (wzorce) Przykład 1: Szablon klasy -
Licznik template<class Count_Type> class Count { public:
Architektura systemu Gra strategiczna „Strusia Jama”
Serwery Aplikacji ASP .NET Web Objects Arkadiusz Popa.
DZIEDZICZENIE · klasy bazowe i klasy pochodne WyświetlAutora( ) Autor
Inżynieria oprogramowania Lecture XXX JavaTM – część IV: IO
Obiektowe metody projektowania systemów
Struktury.
Zaawansowane techniki obiektowe
Test Doubles Adam Gabryś , v1.1,
Klasy w C++. Deklaracja klasy class NazwaTwojejKlasy { //w tym miejscu piszemy definicje typów, //zmienne i funkcje jakie mają należeć do klasy. }; //tutaj.
Pakiety w Javie Łukasz Smyczyński (132834). Czym są pakiety? Klasy w Javie są grupowane w pewne zbiory zwane pakietami. Pakiety są więc pewnym podzbiorem.
T: Różnice pomiędzy programowaniem strukturalnym a obiektowym
W większości języków programowania biblioteki wejścia/wyjścia ukrywają szczegóły obsługi poszczególnych mediów pod abstrakcją strumienia (ang. stream).
Projektowanie obiektowe
JAVA c.d.. Instrukcji wyboru SWITCH używamy, jeśli chcemy w zależności od wartości pewnego wyrażenia wykonać jeden z kilku fragmentów kodu. Jest to w.
Dziedziczenie Maciek Mięczakowski
Komponentowe systemy rozproszone Wprowadzenie. Komponent... jest to podstawowa jednostka oprogramowania z kontraktowo (deklaratywnie) opisanymi interfejsami,
Programowanie obiektowe Wykład 3 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21 Dariusz Wardowski.
Programowanie obiektowe Wykład 6 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14 Dariusz Wardowski.
Projektowanie obiektowe
Tworzenie Aplikacji Internetowych
Programowanie obiektowe 2013/2014
ZWIĄZKI MIĘDZY KLASAMI KLASY ABSTRAKCYJNE OGRANICZENIA INTERFEJSY SZABLONY safa Michał Telus.
Kurs języka C++ – wykład 9 ( )
Programowanie w języku C++
Dobry kod OO Jeżeli zapytamy statystycznego programistę z czym kojarzy mu się dobry kod OO to najprawdopodobniej będzie mówił o wzorcach projektowych.
UML W V ISUAL S TUDIO Mateusz Lamparski. UML D EFINICJA Unified Modeling Language (UML) to graficzny język do obrazowania, specyfikowania, tworzenia i.
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
Diagram klas Kluczowymi elementami są: klasy (class)
Kurs języka C++ – wykład 4 ( )
Technologie internetowe Wykład 5 Wprowadzenie do skrytpów serwerowych.
OOP, Desing Patterns … and more Michał Dubel
Komponentowe systemy rozproszone Wprowadzenie. Komponent... jest to podstawowa jednostka oprogramowania z kontraktowo (deklaratywnie) opisanymi interfejsami,
Zakres Wzorce projektowe ( -Adapter (str , wykład wzorce projektowe.
Obiektowe metody projektowania systemów Adapter. Wstęp: „Dostosowanie interfejsu klasy do interfejsu, którego oczekuje użytkownik. Adapter umożliwia współprace.
Obiektowe metody projektowania systemów Abstract Factory design pattern (aka. Kit)
Paweł Starzyk Obiektowe metody projektowania systemów
Wzorce Projektowe w JAVA
Programowanie Zaawansowane
PO13-1 / 19 Wykład 13 Wyjątki i ich zgłaszanie Wyłapywanie wyjątków Obsługa wyjątków Wykorzystanie polimorfizmu Filtrowanie wyjątków Błędy w konstruktorach.
Partnerstwo dla Przyszłości 1 Lekcja 28 Dziedziczenie i rodzaje dziedziczenia.
Podstawy informatyki Funkcje Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi.
Komponentowe systemy rozproszone Komponenty i zależności.
ZTO Wprowadzenie do TDD, SOLID - Jak pisać dobry kod Krzysztof Manuszewski.
Inżynieria oprogramowania OOP i zasady SOLID WWW: Jacek Matulewski Instytut Fizyki, UMK.
Programowanie Obiektowe – Wykład 6
ZTO Wprowadzenie do TDD, SOLID - Jak pisać dobry kod
Programowanie Obiektowe – Wykład 9
Strumienie, Wczytywanie, Zapisywanie, Operacje na plikach
Programowanie Obiektowe – Wykład 7
Wątki, programowanie współbieżne
(według:
Delegaty Delegat to obiekt „wiedzący”, jak wywołać metodę.
Programowanie Obiektowe – Wykład 2
PGO Interfejsy Michail Mokkas.
PGO - Projektowanie i implementacja pierwszych klas
Refaktoryzacja czyli odświeżanie kodu
Zapis prezentacji:

Komponentowe i rozproszone Jak pisać dobry kod

ZŁY KOD WYGLĄDA TAK...

... jest sztywny i delikatny Nowe błedy pojawiają się w obszarach, które zdają sie być niezwiazane ze zmienianą funkcjonalnoscią Pozornie drobne zmiany indukują poważne zmiany w wielu miejscach kodu i/lub skutkuja trudnymi do przewidzenia błędami Trudno przewidzieć wpływ nawet drobnych zmian Trudno przewidzieć czas oraz koszty rozwoju projektu/poprawek Zespół prorgramistów traci wiarygodność Menedżerowie niechętnie godza się na zmiany

... i trudny do reużycia Potrzebne elementy zależą od niepotrzebnych Ryzyko ekstrakcji potrzebnego kodu jest duże a koszt wiekszy niż napisanie opotrzebnej funkcjonalności od podstaw

Bezpośrednie źródła problemów Praca z cudzym kodem Pośpiech Zmiany, ciagłe zmiany Niedostateczna/niejasna specyfikacja... a może przyczyną jest nienajlepsza architektura kodu

Prosty przykład public class Copier { public static void Copy() { int c; while((c=Keyboard.Read()) != -1) Printer.Write(c); } kopiowanie znaków z klawiatury na drukarkę

... drobna zmiana... public class Copier { public static bool rdFlag = false; public static void Copy() { int c; while((c=(rdFlag ? PaperTape.Read() : Keyboard.Read()) != -1) Printer.Write(c); } Z klawiatury lub z czytnika taśmy

..i następna... public class Copier { public static bool rdFlag = false; public static bool ptFlag = false; public static void Copy() { int c; while((c=(rdFlag ? PaperTape.Read() : Keyboard.Read()) != -1) if (ptFlag) Screen.Write(c); else Printer.Write(c); } Na drukarke lub ekran

...i już nie jest prosty... Więcej źródeł i ujść danych Obsługa błędów I/O errors Przekodowywanie znaków Logowanie przekodowanych znaków do pliku Zmiana formatu tekstu w oparciu o kontekst (np justowanie tekstu

Wymagania się zmieniają... Zawsze lub przynajmniej czasami zwłaszcza w kontekście iteracyjnej realizacji projektu

public class KeyboardReader : { public int Read() { return Keyboard.Read(); } } public class PrinterWriter : { public Write(int c) { return Printer.Write(c); } } public class Copier { public static KeyboardReader reader = new KeyboardReader(); public static PrinterWriter writer = new PrinterWriter(); public static void Copy() { int c; while((c=(reader.Read())) != -1) writer.Write(c); }... być gotowym na zmiany

... to podzielić odpowiedzialność Jest dużo lepiej – wyraźna separcja kodu: twórcy klas Printer i Writer nie muszą znać ani rozumieć logiki kopiowania ale: Zmiany w sposobie obsługi drukarki/klawiatury: wymuszają zmiany w klasie kopier (typy atrybutów) wymuszają rekompilację klasy Copier Implementujący klasę Copier musi znać i umieć tworzyć obiekty klas Printer, KeyboardReader Klasa Screen musi dziedziczyć po Printer (choć nie ma nic wspólnego z drukarką)

LEPSZYKOD WYGLĄDA TAK...

public interface IReader { public int Read() ; } public class KeyboardReader : IReader{ public int Read() { return Keyboard.Read(); } } public class Copier { public static IReader reader = new KeyboardReader(); public static IWriter writer = new PrinterWriter(); public static void Copy() { int c; while((c=(reader.Read())) != -1) writer.Write(c); }

public class Copier { IReader reader; IWriter writer; public Copier (IReader newReader, IWriter writer) { reader = newReader; writer = newWriter; } public static void Copy() {... }

Dobra separacja kodu Klasa Copier nie zależy od Printer ani od Reader Klasy Printer ani Reader nie zależą od Copier Wszystkie klasy (usługobiorcy i usługodawcy zależą od interfejsu) Zmiany interfejs-u sa jedynym powodem do zmian w większych obszarach kodu Interfejs stanowi specyfikację kontraktu pomiędzy 2 stronami – klientem i dostarczycielem pewnej funkcjonalności

S.O.L.I.D. - ny kod SRP: The Single Responsibility Principle OCP: The Open/Close Principle LSP: The Liskov Substitution Principle ISP: The Interface Segregation Principle DIP: The Dependency Inversion Principle

(SRP) Single-Responsibility Principle Klasa powinna mieć pojedynczy powód do zmian. Klasa Printer jest odpowiedzialna za pisanie na drukarkę Klasa Copier jest odpowiedzialna za proces kopiowania

SRP - przykład problemów 2 odpowiedzialności razem – zarządzanie połaczeniem i transmisja danych Jeżeli klienci korzystają z nich oddzielnie (prawdopodobne) zmiany w sygnaturze Dial wywołają konieczność rekompilacji klientów, którzy korzystają jedynie z Send/Recv public interface Modem { public void Dial(string pno); public void Hangup(); public void Send(char c); public char Recv(); }

SRP - przykład problemów Nie zmusza do realizacji obu funkcjonalności przez jedną klasę – chociaz dalej jest to mozliwe

SRP - przykład problemów Zmiany dowolnego z 3 aspektów oznaczają zmiany w klasie Employee Łatwo wprowadzić błąd do pobocznej funkcjonalności. Testować trzeba cała klasę. Pożądane jest ograniczenie funkcjonalności w obrębie zmienianej klasy

SRP - Możliwe rozwiązanie

Moment! Obiekty powinny hermetyzować swoją zawartość Obiekty powinny mieć wiedzę jak realizować zadania Hak zapisać samego siebie? Jak raportować swój stan? To nie jest tak istotne! Filozofia która kryje się za OO nie jest w tym wypadku tak istotna Podstawowym celem jest ograniczenie propagacji zmian w systemie System ma być łatwy w utrzymaniu i modularny!

(OCP) Open/Close Principle Jednostki programowe (klasy, moduły, funkcje, itd.) powinny być otwarte na modyfikacje a zamknięte na zmiany Rober C.C Martin Do kopiarki mogą być łatwo dodawane nowe typy czytników/pisarzy bez zmian (no prawie bez) w klasie Copier Ale bez zmian oznacza też, że klasa Copier nie powinna sama tworzyć obiektów, z których korzysta -> rozwiązywanie zależności

OCP - Otwartość na rozszerzanie Zapewniają np. wzorce projektowe: strategia metoda szablonowa Które rozwiązanie wybrać ?

Które rozwiazanie wybrać? Dziedziczenie wprowadza silniejsze zwiazki miedzy klasami: Agregacja daje możliwość zmiany zachowania w runetime Agregacje dają możliwość niezależnego określania zachowania niezaleznych strategii Dziedziczenie interfejsu jest naturalne Dziedziczenie implementacji niekoniecznie Jeśli nie ma dodatkowych wskazówek agregacja może być lepszym rozwiazaniem!

OCP – co ze zmianami? Nie można zapobiec wszystkim zmianom Kluczowe jest rozpoznanie co może się zmieniać często lub co bedzie trudno zmienić. Dodanie nowej funkcjonalności powinno być łatwe

(LCP) Liskov Substitution Principle Podklasy muszą być logicznie zgodne z typami bazowymi. TapeReader : KeyboardReader ??? Dziedziczenie oznacza jest szególnym przypadkiem OCP relies on inheritance What are design rules? What are characteristics of good inheritance hierarchies? What are traps we should avoid?

public class Rectangle { private Point topLeft; private double width; private double height; public double Width { get { return width; } set { width = value; } } public double Height { get { return height; } set { height = value; } } LCP – Szkolny przykład (1)

Unit Testing public class Rectangle { private Point topLeft; private double width; private double height; public virtual double Width { get { return width; } set { width = value; } } public virtual double Height { get { return height; } set { height = value; } } public class Square : Rectangle { public override double Width { set { base.Width = value; base.Height = value; } public override double Height { set { base.Height = value; base.Width = value; } LCP – Szkolny przykład (2)

Unit Testing void foo (Rectangle r) { r.SetWidth(32); // calls Rectangle.SetWidth } Co bedzie gdy przekażemy obiekt typu Square? A poniżej ? void goo (Rectangle r) { r.Width = 5; r.Height = 4; if(r.Area() != 20) throw new Exception("Bad area!"); } Square nie zachowuje się jak szczególny przypadek prostokąta! LCP – Szkolny przykład (3)

(ISP) Interface Seggregation Principle Klasa nie powinna zależeć od tego, czego nie używa. Interfejs IReader powinien być oddzielny od IWriter. Tłuste klasy wprowadzają zwykle silne związki ze swoimi klientami Zmiana wymuszona przez jednego z klientów dotyka pozostałych

ISP - uwagi Należy unikać obszernych interfejsów Interfejs (kontrakt) powinien być spójny Interfejs (kontrakt) nie powinien być zbyt szeroki wszystkie implementujące go klasy będą musiały dostarczyć kompletu metod (np. WCF: 3-5-9) Lepsze są wąskie, zorientowane na role interfejsy Jeżeli nie można uniknąć tłustych klas - te powinny być prezentowane klientom za pośrednictwem zbioru wąskich, zorientowanych na role interfejsów Oddzielni klienci mogą oznaczać oddzielne interfejsy Interfejsy moga dziedziczyc po sobie – można dostarczyć pojedynczą referencją do obiektu implementującego wiele interfejsów.

(DIP) Dependency-Inversion Principle 1. Wysokopoziomowe moduły nie powinny zależeć od nispopoziomowych (ani odwrotnie). Jedne i drugie powinny zależeć od abstrakcji (kontraktów). 2. Abstrakcje (kontrakty) nie powinny zależeć od szczegółów implementacyjnych. Implementacja powinna zależeć od abstrakcji (kontraktu). Hollywood principle: Dont call us – we will call you Copier i KeyboardReader zależą od interfejsu IReader, ale nie zależą od siebie Interfejs jest bardziej przejrzysty niż klasa

Unit Testing DIP - Przykład

Unit Testing DIP - podsumowanie Podstawa dobrego OOD Interfejsy należą do klientów Implementacja zmienia się często, interfejsy rzadko Podejrzane sytuacje: Zmienna odwołuje się do nieabstrakcyjnej klasy Klasa dziedziczy po nieabstrakcyjnej klasie Metoda nadpisuje konkretną implementację z klasy bazowej

Zalecana lektura Robert C.C. Martin Agile Principles, Patterns and Practices in C# Warto zobaczyc screencast martina z NDC 2009 Robert C. Martin - Clean Design, SOLID Principles I and II.wmv