1 / 31

Programowanie komponentowe jesień-zima 2013

Programowanie komponentowe jesień-zima 2013. Wykład 4 Cykl życia komponentu Wzorce projektowe Programowanie obiektowe w C#. dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki http://wbieniec.kis.p.lodz.pl/pwsz. Cykl życia komponentu.

dorit
Télécharger la présentation

Programowanie komponentowe jesień-zima 2013

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Programowanie komponentowejesień-zima 2013 Wykład 4 Cykl życia komponentu Wzorce projektowe Programowanie obiektowe w C# dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki http://wbieniec.kis.p.lodz.pl/pwsz

  2. Cykl życia komponentu Każdy komponent jest zarządzany przez kontener. W czasie swojego życia, komponent może jednak mieć wpływ na swoją inicjalizację, konfigurację i usuwanie. Jest to możliwe dzięki temu, że istnieje kontrakt kontrakt pomiędzy komponentem deklarującym określone metody odpowiadające tym etapom, a kontenerem, który we właściwym momencie je wywoła. Komponent nie ma możliwości wpływania na kolejność ani moment wywoływania tych procedur

  3. Reprezentacje cyklu życia komponentu 1. Poprzez specjalizowane interfejsy związane z danym kontenerem, które definiują metody reprezentujące poszczególne etapy życia komponentu • silne powiązanie z kontenerem • duża liczba interfejsów 2. Poprzez bezpośrednie podanie nazw metod związanych z konkretną fazą życia komponentu podczas jego konfiguracji. • elastyczne • bardzo prosty mechanizm konfiguracji

  4. Cykl życia definiowany przez interfejs INICJALIZACJA OBSŁUGA ŻĄDAŃ USUNIĘCIE 1. konstruktor 2. contextualize() 3. compose() 4. configure() 5. parametrize() 6. initialize() 7. start() 1.suspend() 2. recontextualize() 3. recompose() 4. reconfigure() 5. reparametrize() 6. resume() 1. stop() 2. dispose() 3. finalizacja Przykład - kontener Apache Avalon Fortress. Duża liczba możliwych do wywołania metod – programista może uwzględnić każdy etap w cyklu życia komponentu. Wada – konieczność implementacji wielu interfejsów związanych z konkretnym kontenerem

  5. Cykl życia definiowany przez nazwy metod Rozwiązanie to daje ono potencjalnie większe możliwości konfiguracji komponentu. Polega na określaniu nazw metod wywoływanych w typowych fazach życia komponentu i przekazaniu ich kontenerowi w postaci konfiguracji. Przykład – Spring. komponent Ksiazka posiada metodę inicjuj() wywoływaną tuż po utworzeniu instancji obiektu oraz metodę usun() wykonywaną przed usunięciem instancji komponentu z rejestru. <bean id="Ksiazka" class="elearning.Ksiazka" init-method="inicjuj" destroy-method="usun"> <property name="karta" /> </bean>

  6. Styl życia komponentu Liczba instancji komponentu prototyp: każde żądanie tworzy nową instancję Kontener tworzy komponenty-wartości – instancje są tworzone w odpowiedzi na każde żądanie. singleton: istnieje jedna współdzielona instancja Kontener tworzy komponenty-referencje (podobne do obiektów-referencji), których jedyna instancja jest współdzielona przez wszystkich żądających do niej dostępu klientów. • Moment tworzenia komponentu • • eager (zachłanny): przy starcie kontenera • • lazy (leniwy): gdy będzie potrzebny

  7. Dygresja – wzorce projektowe Wzorzec projektowy (design pattern) – w inżynierii oprogramowania, uniwersalne rozwiązanie powtarzalnych problemów projektowych. Pokazuje powiązania i zależności pomiędzy klasami oraz obiektami i ułatwia tworzenie, modyfikację oraz pielęgnację kodu źródłowego. Jest opisem rozwiązania. Kreacyjne – opisują proces tworzenia, inicjalizacji i konfiguracji nowych obiektów. Przykłady: Budowniczy, Fabryka abstrakcyjna, Metoda wytwórcza, Prototyp, Singleton strukturalne – opisują struktury powiązanych ze sobą obiektów; Przykłady: Adapter, Dekorator, Fasada, Kompozyt, Most, Pełnomocnik, Pyłek. czynnościowe – opisują zachowanie współpracujących ze sobą obiektów. Przykłady: Interpreter, Iterator, Łańcuch zobowiązań, Mediator, Metoda szablonowa, Obserwator, Odwiedzający, Pamiątka, Polecenie, Stan, Strategia

  8. Przykłady wzorców projektowych - Singleton Singleton to obiekt, który może istnieć tylko w jednej instancji (tak jak np. obiekt aplikacji w aplikacji MFC lub obiekt Servletu w kontenerze serwletów. Implementacja: Statyczna metoda getInstance. Sprawdza, czy istnieje już instancja tej klasy, w razie potrzeby tworząc ją. Następnie instancja zwracana jest przez referencję. Instancję przechowuje się w prywatnym statycznym polu klasy. Konstruktor klasy jest prywatny – nie można go wywołać operatorem new Przykład w C# sealedclassSingleton { privatestaticreadonlySingletoninstance = newSingleton(); privateSingleton() { / * pusty konstruktor prywatny */ } staticSingleton() { /* pusta metoda statyczna */ } public staticSingletonInstance { /* metoda getInstance */ get { return instance; } } }

  9. Przykłady wzorców projektowych – Adapter Adapter o obiekt, który implementuje w sposób domyślny (lub pusty) wszystkie metody Interfejsu, dzięki czemu łatwiej jest napisać klasę obsługującą ten interfejs. Przykład w Java – obsługa myszy public interface MouseListener extends EventListener { public void mouseClicked(MouseEvent e); public void mousePressed(MouseEvent e); public void mouseReleased(MouseEvent e); public void mouseEntered(MouseEvent e); public void mouseExited(MouseEvent e); } public abstractclassMouseAdapterimplementsMouseListener { public voidmouseClicked(MouseEvent e) {} public voidmousePressed(MouseEvent e) {} public voidmouseReleased(MouseEvent e) {} public voidmouseEntered(MouseEvent e) {} public voidmouseExited(MouseEvent e) {} }

  10. Przykłady wzorców projektowych – Adapter public class MyApp1 implementsMouseListener { JFrame f = newJframe("Hello"); MyApp1(){ f.setVisible(true); f.addMouseListener(this); } public voidmouseClicked(MouseEvent e) { f.setBackground(Color.red); } public voidmousePressed(MouseEvent e) {} public voidmouseReleased(MouseEvent e) {} public voidmouseEntered(MouseEvent e) {} public voidmouseExited(MouseEvent e) {} } public class MyApp2 extendsMouseAdapter{ JFrame f = newJframe("Hello"); MyApp2(){ f.setVisible(true); f.addMouseListener(this); } public voidmouseClicked(MouseEvent e) { f.setBackground(Color.red); } }

  11. Przykłady wzorców projektowych – obserwator Obserwator to obiekt, który raportuje zmiany stanu obiektu obserwowanego. Działa tak, że zmiana w obiekcie obserwowanym wywołuje specyficzne zdarzenia, na które możemy reagować. Przykład – użycie obiektu ImageObserwer w Javie, pozwalającego obserwować proces ładowania obrazu • Aby obserwować ładowanie obrazka, należy zdefiniować metodę imageUpdate(...) interfejsu ImageObserver. Każdy komponent jest z natury ImageObserverem. • Metoda imageUpdate jest wołana za każdym razem, gdy informacja o obrazie jest dostępna. Uzyskuje ona tę informację w postaci infoflag.

  12. Użycie obiektu ImageObserver • Aby obserwować ładowanie obrazka, należy zdefiniować metodęimageUpdate(...) interfejsu ImageObserver. Każdy komponent jest z natury ImageObserverem. • MetodaimageUpdate jest wołana za każdym razem, gdy informacja o obrazie jest dostępna. Uzyskuje ona tę informację w postaci infoflag. import javax.swing.*; class Kanwa extends JPanel { Image img; String itit; int width, height; boolean imageReady = false, imageError = false, firstPaintDone = false; Kanwa (String s,Image im, int w, int h) { itit=s; img = im; width = w; height = h; }

  13. Użycie obiektu ImageObserver publicboolean imageUpdate(Image theImg, int Infoflags,int x,int y, int w,int h) { if (infoflags & (ERROR)) != 0) ImageError=true; else if ((infoflags & (WIDTH | HEIGHT)) != 0) { width = w; height = h; } imageReady=((infoflags & (ERROR|FRAMEBITS|ALLBITS)) != 0); if (imageReady) repaint(); return !imageReady; } Ta metoda jest automatycznie wywoływana przez proces ładowania obrazu i program może odczytywać stan obiektu (tu: aktualizować zmienne imageReady, width oraz height)

  14. Przykłady publicvoid paint(Graphics g) { int w = getSize().width; int h = getSize().height; g.setFont(new Font("Helvetica", Font.BOLD, 14)); g.drawRect(0, 0, w-1, h-1); g.drawLine(0,30, w-1,30); g.drawLine(0, h-40 , w, h-40); g.drawString(name,(w-g.getFontMetrics().stringWidth(name))/2,20); String s = "Gotowe!"; if (!imageReady){ s = "Czekaj ... "; g.drawString(s,(w - g.getFontMetrics().stringWidth(s))/2,h-10); } else { if (imageError) s = "Wadliwy obrazek!"; g.drawString(s,(w - g.getFontMetrics().stringWidth(s))/2,h-10); if (!firstPaintDone){ ((JFrame) getParent()).pack(); firstPaintDone = true; } } if (!imageError) g.drawImage(img, 5, 40, w-10, h-90, this); }

  15. Przykłady wzorców - Budowniczy Budowniczy (Builder) – element programowania komponentowego. Obiekt, który konstruuje inny obiekt (najczęściej kilkuetapowo, gdyż złożony jest z mniejszych komponentów). Rozdziela algorytm tworzenia obiektu od reprezentacji obiektów. Różne warianty omawianego wzorca wykorzystywane są w bibliotece MFC, implementując architekturę dokument/widok. Obiekt klasy CDocument oraz jego podobiekty tworzone są poprzez wywołanie metody tworzącej z trzema parametrami typu CRuntimeClass. Klasa ta zawiera metodę CreateObject, umożliwiającą jej tworzenie obiektów różnych klas (m.in. CDocument, CFrameWnd oraz CView). Dzięki takiemu zachowaniu CRuntimeClass może być nazwana klasą Budowniczego. //Przykład tworzenia pizzy wC#. class Pizza { stringciasto; stringwierzch; stringsos; publicstringCiasto{get{returnciasto;}set{ciasto=value;}} publicstringWierzch{get{returnwierzch;}set{wierzch=value;}} publicstringSos{get{returnsos;}set{sos=value;}} publicoverridestring ToString(){ returnstring.Format("Pizza z ciasta {0}, z sosem {1} i wierzchem {2}", Ciasto, Sos, Wierzch); } }

  16. Przykłady wzorców - Budowniczy //Budowniczy abstrakcyjny abstractclass PizzaBuilder { protected Pizza pizza; public Pizza Pizza {get{return pizza;}} publicvoid CreateNewPizza(){ pizza =new Pizza();} publicabstractvoidBudujCiasto(); publicabstractvoidBudujSos(); publicabstractvoid BudujWierzch(); } //Budowniczy konkretny class Hawajska_PizzaBuilder : PizzaBuilder { publicoverridevoid BudujCiasto(){ pizza.Ciasto="grube";} publicoverridevoidBudujSos(){ pizza.Sos="majonez";} publicoverridevoidBudujWierzch(){ pizza.Wierzch="szynka/ananas";} } //Budowniczy konkretny classPikantna_PizzaBuilder : PizzaBuilder { publicoverridevoid BudujCiasto(){ pizza.Ciasto="cienkie";} publicoverridevoid BuildSos(){ pizza.Sos="ostry ketchup";} publicoverridevoid BuildWierzch(){ pizza.Wierzch="pepparoni+salami";} }

  17. Przykłady wzorców - Budowniczy classKucharz{ private PizzaBuilder pizzaBuilder; public PizzaBuilder PizzaBuilder { get{return pizzaBuilder;} set{ pizzaBuilder =value;} } public Pizza Pizza {get{return pizzaBuilder.Pizza;}} publicvoid ConstructPizza(){ pizzaBuilder.CreateNewPizza(); pizzaBuilder.BudujCiasto(); pizzaBuilder.BudujSos(); pizzaBuilder.BudujWierzch();}} publicclass TestPizza { privatestaticvoid BuildAndDisplayPizza(Kucharzk){ k.ConstructPizza(); System.Console.WriteLine(k.Pizza); } publicstaticvoid Main(){ Kucharz k=newKucharz(); k.PizzaBuilder=new Hawajska_PizzaBuilder(); BuildAndDisplayPizza(k); k.PizzaBuilder=newPikantna_PizzaBuilder(); BuildAndDisplayPizza(k);}}

  18. Budowniczy a Fabryka obiektów W przypadku korzystania z Budowniczego obiekt może być budowany „na raty”. Budowniczy udostępnia kilka metod, którymi stopniowo buduje obiekt. Porównaj StringBuilder. Fabryka zwraca nam gotowy obiekt przy jednym wywołaniu. Przykład – Java – Zakładamy istnienie fabryki abstrakcyjnej i fabryk konkretnych (dla poszczególnych platform systemowych. Fabryka tworzy obiekty – przyciski. abstractclass GUIFactory { publicstatic GUIFactory getFactory() { int sys = readFromConfigFile("OS_TYPE"); if(sys ==0) returnnew WinFactory(); else returnnew OSXFactory(); } publicabstractButton createButton(); }

  19. Fabryka obiektów classWinFactoryextendsGUIFactory{ publicButtoncreateButton(){returnnewWinButton();} } classOSXFactoryextendsGUIFactory{ publicButtoncreateButton(){returnnewOSXButton();} } abstractclassButton{publicabstractvoid paint();} classWinButtonextendsButton{ publicvoid paint(){System.out.println("PrzyciskWinButton");} } classOSXButtonextendsButton{ publicvoid paint(){System.out.println("PrzyciskOSXButton");} } publicclass Application { publicstaticvoid main(String[]args){ GUIFactory factory =GUIFactory.getFactory(); Buttonbutton=factory.createButton(); button.paint(); } }

  20. Dekorator Klasę możemy wzbogacić poprzez dziedziczenie. Można to robić na etapie kompilacji. Dekorator pozwala na wzbogacenie istniejącego w pamięci obiektu nie naruszając stanu obiektu. Obiekt można dekorować wielokrotnie i w dowolnej kolejności Przykład w Javie – obsługa strumieni File plik = new File("test.txt"); //Otwieramy plik // dekorujemy plik, jako strumień wejściowy FileInputStream fstream = new FileInputStream(plik); // dekorujemy strumień – odczyt liczb zapisanych binarnie DataInputStream in = new DataInputStream(fstream); //ponowna dekoracja – umożliwia zmianę kodowania bajty na znaki InputStreamReader is = new InputStreamReader(in); //ponowna dekoracja – umożliwia odczyt linia po linii BufferedReader br = new BufferedReader(is);

  21. Dekorator – implementacja Zwykle dekorator implementujemy jako klasę dziedziczącą po udekorowanej klasie, zawierającą dodatkowo wskaźnik (lub referencję) na dekorowany obiekt /** Klasa, którą będziemy dekorować */ public class Book{ String author; String title; int pages; public String toString(){ return ("|" + author + "|" + title + "|" + pages + "|"); } public Book(String author, String title, int pages){ this.author = author; this.title = title; this.pages = pages; } public String getAuthor(){return author;} public String getTitle() {return title; } public int getPages() {return pages; } }

  22. Dekorator – implementacja /** abstrakcyjny dekorator */ public abstract class CoverIndex extends Book{ protected Book decorBook; //referencja na obiekt public CoverIndex(Book decorBook){this.decorBook = decorBook;} } public class CoverClassic extends CoverIndex{ public CoverClassic(Book decorBook){super(decorBook);} public String toString(){ return decorBook.toString() + "| Classic Cover"; } } public class CoverHard extends CoverIndex{ public CoverHard(Book decorBook){super(decorBook);} public String toString(){ return decorBook.toString() + "| Hard Cover"; } } public class CoverDecorative extends CoverIndex{ public CoverDecorative(Book decorBook){super(decorBook);} public String toString(){ return decorBook.toString() + "| Decorative Cover"; } }

  23. Dekorator – implementacja class Main{ public static void main(String args[]) { Book b = new Book("Mickiewicz" , "Dziady", 300); b = new CoverDecorative(b); //Dekoracja w oprawę ozdobną b = new CoverHard(b); //dekoracja w oprawę twardą System.out.println(b); // Mickiewicz | Dziady | 300 | Decorative Cover | Hard Cover } }

  24. Konfiguracja rejestru kontenera w Spring W Java Spring komponenty konfigurujemy w pliku applicationContext.xml <beans> <!-- wstrzykiwanie przez konstruktor --> <bean id="samochod1" class="lab.Samochod"> <constructor-arg> <ref bean="silnik"/> </constructor-arg> </bean> <!-- wstrzykiwanie przez właściwość --> <bean id="samochod2" class="lab.Samochod"> <property> <ref bean="silnik"/> </property> </bean> <bean id="silnik" class="lab.Silnik1_6"/> </beans> Plik definiuje dwa komponenty typu Samochód. Komponent dostępny pod nazwą samochod1 wykorzystuje wstrzyknięcie komponentu Silnik przez konstruktor, natomiast pod nazwą samochod2 znajduje się komponent korzystający z wstrzykiwania przez właściwość o nazwie silnik.

  25. Programowanie w C# - część 3

  26. Użycie konsoli http://msdn.microsoft.com/en-us/library/system.console.aspx Metody klasy Console: Beep Gra sygnał poprzez głośnik konsolowy. Clear Czyści bufor konsoli i odpowiadające mu okno. ResetColor przywraca domyślne kolory czcionki i tła dla konsoli SetCursorPosition – ustawia kursor na podanej pozyji SetWindowPosition – ustawia pozycję okna konsolowego. SetWindowSize – ustawia szerokość i wysokość okienka konsolowego (liczba wierszy i kolumn) Właściwości klasy Console: Console.Title = "HelloWorld"; Console.BackgroundColor = ConsoleColor.DarkYellow; boolConsole.GetCapsLock(); sprawdza czy jest wciśnięty klasiszCapsLock In Console.GetCursorSize(); //wyświetla wielkość kursora w procentach wielkości komórki

  27. Zasady obiektowości w C# Większość zasad tworzenia i używania klas jest taka sama jak w Javie lub C++ Korzystanie z obiektu. W C# tak jak w Javie, wszystkiemetodyorazzmiennemusząbyćskładowymiklaslubstruktur. Obiekt tworzymy poprzez operator new. Nie ma operatora delete, ani destruktora. Każdy obiekt dziedziczy z object Klasa1 zmienna1 = new Klasa1(); Odwołanie się do składowych (czyli metod, zmiennych lub właściwości zmienna1.X = 20;//odwołanie się do pola (lub właściwości zmienna1.Metoda1();//wywołanie metody Ukrywanie informacji – modyfikatory dostępu • Metody klasyobject • ToString - domyślna wersja tej metody zwraca w pełni kwalifikowaną nazwę klasy • Equals - domyślnie porównuje referencje • GetHashCode – wartość skrótu dla obiektu

  28. Zasady obiektowości w C# Właściwości (Properties) Właściwość to metoda składowa klasy, wraz z elastycznym mechanizmem odczytu, zapisu i przetwarzania prywatnego pola klasy A, B i P to są właściwości klasy Prostokąt. Używamy ich tak jakby to były pola klasy, w rzeczywistości są to metody class Prostokat{ private int a; private int b; public int A{ get{ return a; } set{ a = (value>0?value:0);} } public int B{ get{ return b; } set{ b = (value>0?value:0);} } public int P{ get { return a*b; } } } Prostokat pr = new Prostokat(); pr.A = 10; pr.B = 20; Console.writeln("Dane prostokąta A={0}, B={1}, pole={2}", pr.A, pr.B, pr.P); Właściwości to bezpieczne akcesory (settery, gettery), które w kontrolowany sposób dają dostęp do pól prywatnych, jednocześnie tak łatwe w użyciu jak pola

  29. Właściwości automatycznie implementowane Gdy deklarujesz właściwości tak, jak w poniższym przykładzie kompilator sam tworzy prywatne anonimowe pola, do których dostęp możliwy jest poprzez akcesoryget i set. class Klient{ public double SumaZakupow{ get; set; } public string Nazwisko { get; set; } public int IdKlienta {get; set; } Klient(double zakupy, string nazwisko, int id) { SumaZakupow = zakupy; Nazwisko = nazwisko; IdKlienta = id; } }

  30. Indekser Indeksery to właściwości sparametryzowane definiowane wewnątrz klas Indekser może otrzymywać na wejściu jeden lub wiele parametrów, a nazwa indeksera jest reprezentowana prze słowo kluczowe this. Oferuje sposób dostępu do kolekcji wartości utrzymywanych w ramach pojedynczego obiektu klasy (jest to odpowiednik przeciążonego operatora indeksowania w C++) • public classTablicaKsiazek { • Ksiazka[] ksiazki; • public Ksiazkathis [int index] { • get { return ksiazki[index]; } • set { if (value!=null) { • ksiazki[index] = value; • } • } • } • TablicaKsiazek polka = new TablicaKsiazek(); • polka[155] = new Ksiazka("Pan Tadeusz"); • polka[0] = new Ksiazka("Dziady");

  31. Klasy wieloplikowe W C# definicja klasy nie musi znajdować się w całości w jednym pliku //Plik1.cs partial class Klasa1 {//częściowa definicja klasy } Załóżmy, że jeden plik z definicją klasy jest do naszej dyspozycji i możemy dodawać tam własny kod, drugi jest uaktualniany przez środowisko Visual Studio i nie powinniśmy go modyfikować. Drugie zastosowanie – praca grupowa Obie części będą tworzyły jedną klasę pod warunkiem, że będą miały tę samą, w pełni kwalifikowaną nazwę, czyli będą znajdować się w tej samej przestrzeni nazw. Wszystkie części muszą być dostępne w czasie kompilacji – nie możemy w ten sposób rozszerzać klas już skompilowanych. //Plik2.cs partial class Klasa1 {//częściowa definicja klasy }

More Related