1 / 23

Programowanie komponentowe jesień-zima 2013

Programowanie komponentowe jesień-zima 2013. Wykład 3 Metody wstrzykiwania zależności. dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki http://wbieniec.kis.p.lodz.pl/pwsz. Rozwiązywanie zależności komponentów.

lluvia
Download Presentation

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 3 Metody wstrzykiwania zależności dr inż. Wojciech Bieniecki Instytut Nauk Ekonomicznych i Informatyki http://wbieniec.kis.p.lodz.pl/pwsz

  2. Rozwiązywanie zależności komponentów Metoda tradycyjna polega na aktywnym wyszukiwaniu instancji komponentów w rejestrze kontenera. Metoda nowoczesna wstrzykiwanie zależności (ang. dependencyinjection). Sposoby wstrzykiwania zależności Interfaceinjection - wstrzykiwanie przez interfejs. Komponenty implementują dedykowany interfejs, poprzez który otrzymują obiekt służący do wyszukiwania zależności Constructorinjection wstrzykiwanie przez konstruktor. Wszystkie zależności komponentu muszą zostać spełnione w momencie jego tworzenia, a ich rozwiązaniem i spełnieniem zajmuje się kontener. Setterinjection wstrzykiwanie przez właściwości obiektu, czyli przekazanie przez kontener referencji do zależnego komponentu przez metody typu setXXX()

  3. Wstrzykiwanie zależności przez interfejs Obiekt wyszukuje zależności poprzez obiekt kontekstu, przekazany jako parametr metody zdefiniowanej w interfejsie Jest to najpopularniejsza metoda rozwiązywania zależności (np. w J2EE mechanizm JNDI lub Naming Service w CORBA). Metoda polega na implementacji w komponencie interfejsu, stanowiącego znacznik wskazujący, że komponent ten wymaga pewnych zależności. Interfejs deklaruje metodę posiadającą parametr, który jest obiektem kontekstu – wyszukiwarką innych obiektów. Komponent w momencie utworzenia otrzymuje od kontenera instancję kontekstu, którą może zapamiętać, a następnie wykorzystać do rozwiązania swoich zależności. • Wady: • silne powiązanie z konkretnym kontenerem, jakie wynika z konieczności implementacji przez komponent. • Gdy dostępny jest jedynie komponent w wersji binarnej – użycie tego sposobu jest niemożliwe. Zalety: • odsunięcie w czasie rozwiązywania zależności • obsługa zależności cyklicznych • łatwe testowanie

  4. Wstrzykiwanie przez interfejs public interfaceServiceable { public void service(ServiceManager manager); } public class Samochod implements Serviceable { privateServiceManager manager = null; private Silnik silnik = null; public void service(ServiceManager manager) { this.manager = manager; this.silnik = (Silnik) manager.lookup("Silnik"); } } Klasa Samochód deklaruje implementację interfejsu Serviceable. Interfejs ten definiuje metodę service(), przyjmującą parametr typu ServiceManagerpełniący rolę obiektu-kontekstu Parametr ten zostanie przekazany komponentowi przez kontener w momencie jego tworzenia poprzez wywołanie metody service(). Obiekt ServiceManager jest wyszukiwarką instancji komponentów w rejestrze kontenera poprzez metodę lookup(), która wyszukuje w rejestrze komponent po nazwie. Komponent Samochód może uzyskać referencję do zależnego komponentu Silnik. WADA: Komponent musi wywołać lookup sam. Rola kontenera ogranicza się do utrzymywania rejestru komponentów i dostarczenia obiektu kontekstu

  5. Wstrzykiwanie zależności przez konstruktor Obiekt otrzymuje wszystkie zależności w postaci parametrów konstruktora Komponent nie musi sam zdobywać zasobów. Komponent deklaruje potrzebę ich wykorzystania w sposób, który jest czytelny dla kontenera i pozwala mu rozwiązać zależności. Odpowiedzialność za dostarczenie zależności jest przeniesiona na kontener. Deklaracja zależności odbywa się poprzez parametry konstruktora Kontener dostarcza obiekty poprzez implementacje tych parametrów Jeżeli korzystając z zarejestrowanych komponentów nie można tego uczynić, utworzenie komponentu zależnego nie jest możliwe i zgłaszane w postaci wyjątku. W przypadku gdy komponent posiada wiele konstruktorów, kontenery próbują utworzyć go korzystając z konstruktora najbardziej specyficznego (tj. o najdłuższej liczbie parametrów), którego zależności mogą rozwiązać.

  6. Wstrzykiwanie zależności przez konstruktor ZALETA: Zapewnienie spójnego stanu komponentu w każdym momencie jego istnienia (co jest jednym z warunków tzw. dobrego obywatelstwa), także bezpośrednio po wywołaniu konstruktora przez komponent. WADA: brak możliwości zrealizowania zależności cyklicznych, tj. takich, w których komponenty zależą od siebie wzajemnie. PRZYKŁAD:W kodzie programu mechanizm ten wymaga jedynie stworzenia w klasie komponentu Samochód konstruktora przyjmującego obiekt o interfejsie Silnik jako parametr. Kontener, tworząc instancję klasy Samochód, musi najpierw utworzyć obiekt typu Silnik, aby przekazać go do właściwego konstruktora. public class Samochod { private Silnik silnik = null; public Samochod(Silnik silnik) { this.silnik = silnik; } }

  7. Wstrzykiwanie zależności przez właściwości Komponent jedynie deklaruje zależności, spełnieniem zajmuje się kontener Do przekazania instancji obiektów zależnych używamy metod, tzwsetterów. Zalety • odsunięcie w czasie rozwiązywania zależności (komponent można skonfigurować dopiero przed samym użyciem) • możliwość obsługi zależności cyklicznych (nie było to możliwe w poprzedniej metodzie) • łatwe testowanie Wada: • stan niespójny po utworzeniu – obiekt nie jest w pełni zainicjowany. Wprawdzie proces ten zwykle jest realizowany przez kontener, który zapewnia poprawność komponentu w momencie jego wykorzystania, jednak w szczególnych okolicznościach może to spowodować nieprawidłowe zachowanie programu.

  8. Wstrzykiwanie zależności przez właściwości public classSamochod { privateSilnik silnik = null; public Samochod() { } public voidsetSilnik(Silnik silnik) { this.silnik= silnik; } } Klasa Samochód posiada bezparametrowy konstruktor oraz metodę setSilnik(), która przyjmuje obiekt typu Silnik jako argument. Kontener wywoła tę metodę na komponencie, pozwalając mu zapamiętać referencję do przekazanego w postaci parametru obiektu.

  9. 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.

  10. Programowanie w C# - część 2

  11. Zmienne w C# Non-nullable value type Wartość zdefiniowanego typu, np. int, float Nullable value type Wartość zdefiniowanego obiektu oraz null, np.: Nullable<Int32> oznacza liczby typu Int32 (4 bajty ze znakiem) oraz null object null, referencja do obiektu dowolnego typu, referencja do boxowanej wartości dowolnego typu Klasa Null, referencja do instancji klasy, referencja do instancji klasy dziedziczącej Interfejs Null, referencja do instancji klasy implementującej interfejs, referencja do boxowanej wartości typu implementującego interfejs Tablica Null, referencja do instancji tablicy danego lub kompatybilnego typu Delegat Null, referencja do instancji typu delegata

  12. 123 i "Hello world" s Typy referencyjne i wartościowe Dla typów referencyjnych przydzielane są obszary pamięci na zarządzanej stercie, typy wartościowe są inicjalizowane zerami. Zwalnianie pamięci – pamięć na stosie jest zwalniania w momencie, w którym dana zmienna opuszcza bieżący zakres przetwarzania. Zwalnianie pamięci na stercie – odpowiada proces odzyskiwania pamięci (sprawdzany jest licznik referencji) int i = 123; string s = "Hello world"; Zmienne wartości - bezpośrednio zawierają dane Każda zmienna typu wartości reprezentuje oddzielny obszar pamięci, dlatego operacja na jednej zmiennej nie wpływa na drugą. Zmienne lokalne przechowywane w obszarze pamięci zwanym stosem. Z miejscem przechowywania i sposobem zarządzania tym obszarem związany jest czas życia zmiennej. Czas życia zmiennej możemy zdefiniować jako czas, przez który jest zarezerwowana pamięć dla zmiennej. Pamięć jest zarezerwowana dla zmiennej lokalnej od miejsca jej zadeklarowania do końca bloku, w którym została zadeklarowana. Przed użyciem zmienna musi być zainicjalizowana - musi mieć nadaną wartość.

  13. Typy nullable Dla wszystkich typów wartości wprowadzono pewną formę typu (nullabletypes), której zmienne mogą przyjmować wartości null (wartość nieokreślona). Typy nullable wprowadzono, aby ułatwić współpracę z bazami danych. classNullableExample { staticvoidMain() { int? num = null; if (num.HasValue) System.Console.WriteLine("num = " + num.Value); else System.Console.WriteLine("num = Null"); int y = num.GetValueOrDefault(); try { y = num.Value; } catch (System.InvalidOperationException e){ System.Console.WriteLine(e.Message); } } }

  14. Boxowanie 123 i int i = 123; object o = i; int j = (int)o; System.Int32 o 123 123 j W języku C# istnieje jeszcze standardowa konwersja - opakowanie (boxing). Opakowanie wartości polega na niejawnym przekształceniu typu wartości w typ object. Rozpakowanie (unboxing) musi być jawne i może powodować wyjątek. int i = 123; object o = i; // implicit boxing try { int j = (short)o; // attempt to unbox System.Console.WriteLine("Unboxing OK."); } catch (System.InvalidCastException e) { System.Console.WriteLine("{0} Error: Incorrect unboxing.", e.Message); }

  15. Typ wbudowany string publicsealedclassString : IComparable,ICloneable, IConvertible, IEnumerable{ publiccharthis[intindex] {get;} publicintLength {get;} publicstaticintCompare(stringstrA,stringstrB); publicstaticintCompareOrdinal(stringstrA,stringstrB); publicstaticstringFormat(stringformat,objectarg0); publicintIndexOf(string); publicintIndexOfAny(char[] anyOf); publicintLastIndexOf(stringvalue); publicstringPadLeft(intwidth,charc); publicstring[] Split(paramschar[] separator); public string Substring(intstartIndex,intlength); ... } • Łańcuchy : • łańcuch jest sekwencją wartości typu char • porównywane są według wartości • niezmienne (ang. immutable) – zmodyfikowane są zapisywane pod innymi adresami niż oryginalne string s = "Hi there."; Console.WriteLine( "{0}", s.ToUpper() ); // Print uppercase copy Console.WriteLine( "{0}", s ); // String is unchanged

  16. Przykłady testowania stringów string s1 = "Hello!"; string s2 = "Yo!"; Console.WriteLine("s1 = {0}", s1); Console.WriteLine("s2 = {0}", s2); Console.WriteLine(); // UWAGA == porównuje referencje a nie obiekty! Console.WriteLine("s1 == s2: {0}", s1 == s2); Console.WriteLine("s1 == Hello!: {0}", s1 == "Hello!"); Console.WriteLine("s1.Equals(s2): {0}", s1.Equals(s2)); Console.WriteLine("Yo.Equals(s2): {0}", "Yo!".Equals(s2)); Console.WriteLine();

  17. Podstawowe operacje na łańcuchach

  18. Znaki specjalne w łańcuchach Łańcuchy standardowe i dosłowne (ang. verbatim) string rst1 = "Hi there!"; string vst1 = @"Hi there!"; string rst2 = "It started, \"Four score and seven...\""; string vst2 = @"It started, ""Four score and seven..."""; string rst3 = "Value 1 \t 5, Val2 \t 10"; string vst3 = @"Value 1 \t 5, Val2 \t 10"; string rst4 = "C:\\Program Files\\Microsoft\\"; string vst4 = @"C:\Program Files\Microsoft\"; string rst5 = " Print \x000A Multiple \u000A Lines"; string vst5 = @" Print Multiple Lines";

  19. Łańcuchy zmienne - StringBuilder StringBuildermyBuffer = newStringBuilder ("Ala ma kota"); myBuffer.Append(" a Ola psa."); myBuffer.Insert(11, ','); string Ready =myBuffer.ToString();// Ala ma kota, a Ola psa. • KlasaSystem.Text.StringBuilder • konstruowanie i przetwarzanie łańcuchów składowanych w buforze • bardziej efektywne w przetwarzaniu łańcuchów public sealed class StringBuilder { public intCapacity {get; set;} public intLength {get; set;} StringBuilder Append(...); StringBuilderAppendFormat(...); StringBuilder Insert(int index, ...); StringBuilder Remove(intstartInd, intlen); StringBuilder Replace(char oldCh, char newCh); stringToString(); }

  20. Typ wyliczeniowy – System.Enum • Typy zawierające zbiór nazwanych stałych • Łatwiejsze czytanie kodu – przypisanie łatwo identyfikowalnych nazw do wartości; • Łatwość pisania kodu – IntelliSense podpowiada listę możliwych wartości; • Łatwość utrzymania kodu - pozwala zdefiniować zbiór stałych i zadeklarować zmienne, które będą akceptować wartości tylko z tego zbioru Definiuje się go przy pomocy słowa kluczowego enum, po którym występuje nazwa nowego typu, a następnie w nawiasach klamrowych podajemy nazwy symboliczne dopuszczalnych wartości, oddzielone przecinkami. Można również przypisać w sposób jawny wartości poszczególnym elementom np.: enum Kolory{czerwony=4, zielony, niebieski=7}; Element zielony ma w sposób niejawny przypisaną wartość 5. Przy definicji typu wyliczeniowego można podać, jaki typ całkowity jest typem bazowym dla definiowanego typu wyliczeniowego. Typem bazowym może być dowolny tym całkowity poza typem char. enumPoryRoku : byte {Wiosna, Lato, Jesien, Zima};

  21. System.Enum – przykład enum Color { Red, Green, Blue }; Color a = Color.Red; Color b = Color.Green; Color c = Color.Blue; Console.WriteLine("Wartości typu Color: "); foreach(string s in Enum.GetNames(typeof(Color))) Console.WriteLine(s); Console.WriteLine("Blue należy do typu Color ?:{0}", Enum.IsDefined(typeof(Color),"Blue")); Console.WriteLine("Yellow należy do typu Color ?: {0}", Enum.IsDefined(typeof(Color), "Yellow"));

  22. Tablice w C# Cechy tablicy: • jednorodność - jest złożona z elementów tego samego typu zwanego typem podstawowym tablicy • swobodny dostęp - wszystkie elementy tablicy są jednakowo dostępne - w dowolnej kolejności i w jednakowym czasie • stała (niezmienna) ilość elementów • ciągłość - zajmuje ciągły obszar pamięci • Pojedynczy element dostępny za pomocą indeksu • typ [] nazwa; // Deklaracja zmiennej tablicowej • nazwa = new typ[liczba_Elementow]; //utworz. obiektu tablicowego • typ2 [] nazwa2 = new typ2[ilosc_Elementow2]; //deklar. z definicją • int[] tab1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

  23. Wbudowane operacje na tablicach Kopiowanie wartości elementów jednej tablicy do drugiej tablicy. int[] tab1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; int[] tab2 = {11,12,13,14,15,16,17,18,19 }; Array.Copy(tab1,2,tab2,4,4); tab2: {11, 12, 13, 14, 3, 4, 5, 6, 19,} Skopiowanie wartości jednej zmiennej tablicowej do drugiej zmiennej tablicowej, spowoduje że obie zmienne tablicowe będą odwoływać się do tego samego obiektu tablicowego. Sortowanie tablicy int[] tab1 = { 4, 1, 83, 41, 53, 36, 47, 18}; Array.Sort(tab1); tab1: {1, 4, 18, 36, 41, 47, 53, 83,} Inne operacje: Reverse – odwracanie kolejności tablicy lub jej fragmentu Exists, FindLast, FindAll, FindIndex, FindLastIndex– przeszukiwanie tablicy lub jej fragmentu

More Related