Zaproszenie do złożenia oferty cenowej

Transkrypt

Zaproszenie do złożenia oferty cenowej
08.09.2013 09:00
Typy obiektowe
Klasy definiowane w bazach danych. Zawierają atrybuty i metody. Typy obiektowe
są czasem nazywane typami definiowanymi przez użytkownika.
Podczas tworzenie typu obiektowego należy stworzyć:
• specyfikację typu obiektowego,
• ciało typu obiektowego.
Specyfikacja typu obiektowego
Uproszczona składnia specyfikacji typu obiektowego:
CREATE [OR REPLACE] TYPE [schemat.]nazwa_typu
[AUTHID {CURRENT_USER|DEFINER}] AS OBJECT (
atrybut1 typ_danych,
[atrybut2 typ_danych,]
[metoda1]
[metoda2]);
/
Ciało typu obiektowego
Uproszczona składnia ciała typu obiektowego:
CREATE [OR REPLACE] TYPE BODY [schemat.]nazwa_typu {IS | AS}
[STATIC | MEMBER] PROCEDURE ciało_procedury
[STATIC | MEMBER | CONSTRUCTOR] FUNCTION ciało_funkcji
[MAP | ORDER] MEMBER FUNCTION ciało_funkcji
/
Atrybuty:
• musi być co najmniej jeden atrybut,
• atrybuty muszą znajdować się przed metodami,
• typ atrybutu:
– dowolny typ bazy danych oprócz: ROWID, UROWID, LONG, LONG RAW, NCHAR, NCLOB,
NVARCHAR2,
– typy PL/SQL oprócz BINARY_INTEGER, BOOLEAN, PLS_INTEGER, RECORD, REF CURSOR,
– typ wbudowany,
– typ zdefiniowany przez użytkownika,
• nie można stosować ograniczenia NOT NULL,
• nie można używać wartości domyślnych.
SELF wskazuje na aktualny obiekt (odpowiednik this w Javie).
Metody
[STATIC | MEMBER] PROCEDURE specyfikacja_procedury
[STATIC | MEMBER | CONSTRUCTOR] FUNCTION specyfikacja_funkcji
[MAP | ORDER] MEMBER FUNCTION ciało_funkcji,
deklaracja_dyrektywy
Metody:
• składowe (MEMBER),
• statyczne (STATIC ),
• konstruktory (CONSTRUCTOR) – dla każdego typu obiektowego istnieje predefiniowany
konstruktor
o takiej samej nazwie i atrybutach jak typ.
Przykład
CREATE OR REPLACE TYPE zespolona AS OBJECT (
re NUMBER(5,2),
im NUMBER(5,2),
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 1 z 39
08.09.2013 09:00
CONSTRUCTOR FUNCTION zespolona(re NUMBER, im NUMBER)
RETURN SELF AS RESULT,
CONSTRUCTOR FUNCTION zespolona(re NUMBER)
RETURN SELF AS RESULT,
MEMBER PROCEDURE dodaj (z zespolona),
MEMBER PROCEDURE drukuj
);
/
Porównywanie i sortowanie
SET SERVEROUTPUT ON
DECLARE
z1 zespolona := zespolona(3,4);
z2 zespolona := zespolona(6);
BEGIN
DBMS_OUTPUT.ENABLE;
IF(z1 < z2) THEN
DBMS_OUTPUT.PUT_LINE('z1 < z2');
ELSIF(z1 > z2) THEN
DBMS_OUTPUT.PUT_LINE('z1 > z2');
ELSE
DBMS_OUTPUT.PUT_LINE('z1 = z2');
END IF;
END;
/
Metody służące do porównywania i sortowania:
• MAP – służy do przekształcenia obiekt na typ umożliwiający sortowanie, zwraca DATE,
NUMBER,
VARCHAR2, CHAR, REAL, jeżeli używane jest dziedziczenie metoda MAP może wystąpić w
typach
pochodnych tylko jeżeli występowała w typie bazowym,
• ORDER – przyjmuje jeden parametr typu obiektowego i zwraca wartość typu NUMBER,
wartość
zwracana jest wynikiem porównania obiektu przekazanego jako parametr z danym obiektem,
jeżeli
używane jest dziedziczenie metoda ORDER musi znajdować się w typie bazowym, a typy
pochodne nie
mogą jej przesłaniać.
Dziedziczenie
Słowa kluczowe związane z dziedziczeniem:
• UNDER nazwa_typu_bazowego – dziedziczenie,
• FINAL – nie można dziedziczyć po typie obiektowym (domyślnie),
• NOT FINAL – można dziedziczyć po typie obiektowym,
• INSTANTIABLE – można tworzyć obiektów danego typu obiektowego (domyślnie),
• NOT INSTANTIABLE – nie można tworzyć obiektów danego typu obiektowego,
• OVERRIDING – przesłonięcie metody z typu bazowego.
Tabele obiektowe
Uproszczona składania tworzenia tabeli obiektowej:
CREATE TABLE nazwa_tabeli OF nazwa_typu_obiektowego;
Widoki obiektowe
create_view::=
CREATE [OR REPLACE]
[[NO] FORCE] [EDITIONING] VIEW [schema.] view
[ ( { alias [ inline_constraint... ]
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 2 z 39
08.09.2013 09:00
| out_of_line_constraint
}
[, { alias [ inline_constraint...]
| out_of_line_constraint
}
]
)
| object_view_clause
| XMLType_view_clause
]
AS subquery [ subquery_restriction_clause ] ;
Kolumna obiektowa
column_properties::=
{ object_type_col_properties
| nested_table_col_properties
| { varray_col_properties | LOB_storage_clause }
[ (LOB_partition_storage [, LOB_partition_storage ]...) ]
| XMLType_column_properties
}...
Funkcje i operatory związane z obiektami
:
• REF - wskaźnik obiektów w tabelach i widokach obiektowych,
• DEREF - zwraca obiekt, na który wskazuje wartość REF,
• IS DANGLING - zwraca prawdę jeżeli REF nie wskazuje na żaden obiekt,
• TREAT - sprawdza w czasie wykonania programu, czy obiekt typ bazowy można potraktować
jako
obiekt jednego z typów pochodnych,
• IS OF - zwraca prawdę jeżeli dany obiekt jest określonego typu,
• VALUE - zwraca obiekt z tabeli i widoków obiektowych.
Diagram klas
„Diagramy klas [27] wykorzystują klasy i interfejsy w celu przedstawienia szczegółów
dotyczących składających się na system elementów oraz zachodzących między nimi powiązań statycznych.”
Widoczność
Widoczność [27]:
+ publiczna: „Jeżeli chcemy, aby atrybut lub operacja były dostępne bezpośrednio dla
dowolnej innej klasy,
należy zadeklarować je jako publiczne”,
# chroniona: „Elementy zadeklarowane jako chronione mogą być używane przez metody
będące częścią
danej klasy, jako również przez metody dowolnej innej, która ją dziedziczy.”
~ pakietowa: „Jeżeli do klasy dodamy atrybut lub operację zadeklarowaną przy użyciu
pakietowego poziomu widoczności, wtedy bezpośredni dostęp do tego niego/niej mają wszystkie klasy w
tym samym
pakiecie.”
– prywatna: „Jedynie klasa, która zawiera element oznaczony jako prywatny, może mieć
dostęp do danych
umieszczonych w prywatnym atrybucie lub też wywoływać prywatną operację”
Atrybuty:
• wpisane (ang. inlined),
• w postaci powiązań z innymi klasami.
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 3 z 39
08.09.2013 09:00
Związki pomiędzy klasami:
• zależność,
• asocjacja,
• agregacja (agregacja częściowa),
• agregacja całkowita (agregacja częściowa, kompozycja, złożenie),
• dziedziczenie (uogólnienie, generalizacja).
http://brasil.cel.agh.edu.pl/~09sbfraczek/diagram-klas,1,11.html
Przypadek użycia
Zasady dotyczące określenia zakresu przypadków użycia:
• „Przypadek użycia musi być zainicjalizowany przez aktora.”
• „Kiedy przypadek użycia zostanie uznany za wykonany, to nie można już do niego nic
przekazywać ani
niczego od niego otrzymywać. Żądana funkcjonalność została wykonana lub wystąpił błąd.”
• „Po zakończeniu działania przypadku użycia system znajduje się w stanie pozwalającym
na ponowne
uruchomienia tego przypadku użycia lub wystąpił błąd.
Style przedstawiania przypadków użycia:
• w pełni sformatowany,
• nieformalny,
• tabela jednokolumnowa,
• tabela dwukolumnowa,
• styl Rational Unified Process.
"Szablon w pełni sformatowanego przypadku użycia <nazwa>
<nazwa powinna być celem w postaci krótkiego aktywnego wyrażenia czasownikowego>
Kontekst użycia: <dłuższe określenie celu; jeśli są potrzebne normalne warunki
wystąpienia>
Zakres: <zakres projektowy; jaki system jest traktowany jako projektowana czarna
skrzynka>
Poziom: <jeden z: streszczenie, cel użytkownika, podfunkcja>
Aktor główny: <nazwa roli dla aktora głównego lub jej opis>
Uczestnicy i interesy: <lista uczestników i ich kluczowych interesów w tym przypadku
użycia>
Warunek początkowy: <jakiego stanu świata oczekujemy na wstępie>
Minimalna gwarancja: <w jaki sposób interesy są chronione przy dowolnym zakończeniu>
Gwarancja powodzenia: <stan świata, gdy cel będzie zrealizowany>
Wyzwalacz: <co uruchamia przypadek użycia; może być zdarzenie zegarowe>
Główny scenariusz powodzenia:
<umieść tu kroki scenariusza od wyzwalacza do realizacji celu i całe późniejsze
sprzątanie>
<numer kroku> <opis akcji>
Rozszerzenia: <umieść tu rozszerzenia, jedno w wierszu; każde odwołuje się do kroku
scenariusza głównego>
<zmieniony krok> <warunek>: <akcja albo podrzędny przypadek użycia>
<zmieniony krok> <warunek>: <akcja albo podrzędny przypadek użycia>
Lista wariantów technologii i danych: <umieść tu warianty, które ostatecznie mogą
spowodować rozdzielenie scenariusza>
<numer kroku lub wariantu> <lista wariantów>
<numer kroku lub wariantu> <lista wariantów>
Dodatkowa informacja: <cokolwiek jest potrzebne w przedsięwzięciu jako dodatkowa
informacja>"
Styl Rational Unified Process [5]
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 4 z 39
08.09.2013 09:00
1. Nazwa przypadku użycia
1.1. Krótki opis
... tekst ...
1.2. Aktorzy
... tekst ...
1.3. Wyzwalacze
... tekst ...
2. Przepływ zdarzeń
2.1. Przepływ podstawowy
... tekst ...
2.2. Przepływy alternatywne
2.2.1. Warunek 1
... tekst ...
2.2.2. Warunek 2
... tekst ...
2.2.3. ...
3. Specjalne wymagania
3.1. Platforma
... tekst ...
3.2. ...
4. Warunki początkowe
... tekst ...
5. Warunki końcowe
... tekst ...
6. Punkty rozszerzenia
... tekst ...
Refaktoryzacja
Brzydkie zapachy:
1. Powielony kod [1]
- w dwóch metodach należących do tej samej klasy,
- w dwóch podklasach tej samej klasy,
- w dwóch niezwiązanych klasach.
Możliwe rozwiązania:
- wydzielenie metody,
- wydzielenie metody i przemieszczenie metody w górę,
- utworzenie metody szablonowej,
- zastąpienie algorytmu,
- wydzielenie klasy.
Utworzenie metody szablonowej
„Dwie metody w podklasach wykonują podobne, ale nie takie same kroki w tej samej
kolejności. Umieść te kroki w metodach o takich samych sygnaturach po to by treść
pierwotnych metod stała się taka sama. Następnie przemieść je do nadklasy.”
abstract class Pracownik {
public int wyliczPensje() {
return wyliczPodstawe() + wyliczPremie();
}
abstract protected int wyliczPodstawe();
abstract protected int wyliczPremie();
}
class Księgowy extends Pracownik {
protected int wyliczPodstawe() {
return 5 * 40;
}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 5 z 39
08.09.2013 09:00
protected int wyliczPremie() {
return (int)(0.1 * 40);
}
}
2. Długa metoda [1]
„kiedy tylko odczuwamy potrzebę umieszczenia w treści metody komentarza wyjaśniającego,
tworzymy zamiast niego nową metodę. Taka metoda zawiera kod, który miał być (lub był)
skomentowany, ale jej nazwa oddaje cel działania kodu, a nie sposób jego osiągnięcia.”
Możliwe rozwiązania:
- wydzielenie metody,
- zastąpienie zmiennej tymczasowej przez zapytanie,
- utworzenie klasy dla grupy parametrów,
- przekazanie całego obiektu,
- zastąpienie metody przez obiekt reprezentujący metodę.
Zastąpienie zmiennej tymczasowej przez zapytanie
„Pewnej zmiennej tymczasowej używa się do przechowywania wyniku obliczeń wartości
jakiegoś wyrażenia. Wydziel obliczanie wartości wyrażenia do oddzielnej metody (której
można teraz używać także w innych miejscach). Zastąp wszystkie referencje do zmiennej
przez wywołania tej metody.
class KontoBankowe {
int wiek;
boolean pelnoletni() {
return wiek > 18;
}
int przelew() {
if (pelnoletni()) {
wykonajPrzelew();
} else {
anuluj();
}
}
}
Zastąpienie metody przez obiekt reprezentujący metodę
„Użycie zmiennych lokalnych w pewnej metodzie uniemożliwia zastosowanie Wydzielenia
metody. Zmień tę metodę w samodzielną klasę tak, by zmienne lokalne stały się polami
tej klasy. Możesz wtedy dzielić metodę, tworząc nowe metody w tej klasie.”
3. Duża klasa [1]
Możliwe rozwiązania:
- wydzielenie klasy,
- wydzielenie podklasy,
- wydzielenie interfejsu.
4. Długa lista parametrów [1]
Możliwe rozwiązania:
- zastąpienie parametru przez metodę,
- przekazanie całego obiektu,
- utworzenie klasy dla grupy parametrów.
Zastąpienie parametru przez metodę
„Wynik wywołania jednej metody przekazuje się jako parametr wywołania następnej. Metoda
pobierająca wartość parametru także może wywołać metodę, która te wartość dostarcza.
Usuń parametr i pobieraj potrzebną wartość bezpośrednio wewnątrz metody, w której jest
potrzebna.”
5. Rozbieżna zmiana [1]
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 6 z 39
08.09.2013 09:00
„Mówimy o rozbieżnej zmianie, jeśli pewna klasa jest często modyfikowana, na różne
sposoby i z rozmaitych powodów. Jeżeli przyglądasz się klasie i mówisz: 'No cóż, trzeba
będzie zmienić te trzy metody zawsze, gdy pojawi się nowa baza danych; a te cztery
metody za każdym razem, gdy pojawi się nowy instrument finansowy', to jest to
prawdopodobnie sytuacja, kiedy dwa obiekty byłyby lepsze niż jeden.”
Możliwe rozwiązania:
- wydzielenie klasy.
6. Poszatkowanie [1]
„Poszatkowanie przypomina rozbieżną zmianę, ale jest jej przeciwieństwem. Stepuje
zawsze wtedy, gdy wprowadzenie zmiany zmusza do wykonania wielu drobnych modyfikacji w
różnych klasach.”
Możliwe rozwiązania:
- przemieszczenie metody,
- przemieszczenie pola,
- rozwinięcie klasy (usunięcie klasy po przemieszczeniu wszystkich jej elementów do
innej).
7. Zazdrość o kod [1]
„Podstawowym zadaniem obiektów jest grupowanie razem danych i operacji na tych danych.
Często spotykanym brzydkim zapachem jest metoda, która wydaje się bardziej
zainteresowana klasą inną niż własną. Najczęstszym przedmiotem takiej zazdrości są
dane.”
Możliwe rozwiązania:
- przemieszczenie metody,
- wydzielenie metody i przemieszczenie metody,
8. Zbitki danych [1]
„Elementy danych są jak dzieci; lubią trzymać się razem. Często widuje się te same trzy
lub cztery elementy danych w wielu miejscach: pola w kilku klasach, parametry w
sygnaturach różnych metod. Zbitki danych powinno się umieścić w osobnym obiekcie.”
Możliwe rozwiązania:
- wydzielenie klasy,
- utworzenie klasy dla grupy parametrów lub przekaż całego obiektu.
9. Obsesja typów podstawowych [1]
„Początkujący programiści obiektowi niechętnie używają małych obiektów do wykonywania
małych zadań, takich jak klasa reprezentująca pieniądze (lub parę składającą się z
liczby i nazwy waluty), klasa reprezentująca zakres (czyli górna i dolna wartość) albo
specjalnego rodzaju napisy, na przykład numery telefonu bądź kody pocztowe.”
Możliwe rozwiązania:
- zastąpienie prostych danych przez obiekt,
- zastąpienie liczby oznaczającej typ przez klasę,
- zastąpienie liczby oznaczającej typ przez podklasy,
- zastąpienie liczby oznaczającej typ przez wzorzec Stan / Strategia,
- wydzielenia klasy (dla pól),
- utworzenia klasy dla grupy parametrów (dla parametrów),
- zastąpienie tablicy przez obiekt (dla tablic).
Zastąpienie prostych danych przez obiekt
„Pewna porcja danych wymaga dodatkowego kodu lub kolejnych danych. Zastąp te dane przez
obiekt.”
Zastąpienie liczby oznaczającej typ przez klasę
„Pewna klasa zawiera niewpływającą na jej działanie liczbę oznaczającą typ. Zastąp tę
liczbę nową klasą.”
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 7 z 39
08.09.2013 09:00
class Osoba
int
int
int
int
int
}
{
grupa0 = 0;
grupaA = 1;
grupaB = 2;
grupaAB = 3;
grupaKrwi = grupa0;
enum GrupaKrwi {
GRUPA_0, GRUPA_A, GRUPA_B, GRUPA_AB
}
class Osoba {
GrupaKrwi g = GrupaKrwi.GRUPA_0;
}
Zastąpienie liczby oznaczającej typ przez podklasy
„Niezmienna wartość liczbowa oznaczająca typ wpływa na działanie pewnej klasy. Zastąp
użycie takiej liczby przez podklasy.”
class Socket {
int UDP = 0;
int TCP = 1;
int type = UDP;
public void send(){
if(type == TCP){
...
} else (type == UDP){
...
}
}
}
abstract class Socket {
abstract public void send();
}
class TCPSocket extends Socket{
public void send(){
...
}
}
class UDPSocket extends Socket{
public void send(){
...
}
}
Zastąpienie liczby oznaczającej typ przez wzorzec Stan / Strategia
„Pole przechowuje liczbę oznaczającą typ, której wartość ma wpływ na dzianie programu,
ale nie można użyć dziedziczenia. Zastąp to pole przez obiekt oznaczający stan.”
class Socket extends ABCD {
int UDP = 0;
int TCP = 1;
int type = UDP;
public void send(){
if(type == TCP){
...
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 8 z 39
08.09.2013 09:00
} else (type == UDP){
...
}
}
}
abstract class SocketImpl{
abstract void send();
}
class UDPSocketImpl extends SocketImpl{
public void send(){... }
}
class TCPSocketImpl extends SocketImpl{
public void send(){...}
}
class Socket extends ABCD {
private SocketImpl s;
Socket(SocketImpl s){
this.s = s;
}
public void send(){
s.send();
}
}
Zastąpienie tablicy przez obiekt
Na podstawie tablicy tworzona jest klasa. Następnie w kodzie tablica jest zastępowana
przez obiekt tej
klasy.
String [] osoba = {"Jan", "Kowalski", "01.01.1951"};
Class Osoba {
String imie;
String nazwisko;
Date dataUrodzenia;
Osoba(String imie, String nazwisko, Data dataUrodzenia){
this.imie = imie;
this.nazwisko = nazwisko;
this.dataUrodzenia = dataUrodzenia;
}
}
10. Instrukcje switch [1]
„Jedną z najbardziej widocznych cech kodu obiektowego jest brak w nim instrukcji switch
(…) Jeśli występuje instrukcja switch, zwykle powinno się rozważyć użycie
polimorfizmu.”
Możliwe rozwiązania:
- wydzielenie metody dla instrukcji switch i przemieszczenie metody, zastąpienie liczby
oznaczającej typ przez podklasy lub zastąpienie liczby oznaczającej typ przez wzorzec
Stan / Strategia, zastąpienie wyrażenia warunkowego przez polimorfizm,
- zastąpienie użycia parametru przez wyspecjalizowane metody.
Zastąpienie wyrażenia warunkowego przez polimorfizm
„W wyrażeniu warunkowym wybrany kod zależy od typu określonego obiektu. Umieść kod
każdej z gałęzi w przedefiniowanej metodzie odpowiedniej podklasy i zmień pierwotną
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 9 z 39
08.09.2013 09:00
metodę na abstrakcyjną.”
class Kredyt{
int wyliczOplate(){
switch (type){
case HIPOTECZNY:
return 0.01 * wartosc;
case SAMOCHODOWY:
return 100 + 0.05 * wartosc;
case KONSUMPCYJNY:
return 300;
}
}
}
abstract class Kredyt {
abstract int wyliczOplate();
}
class KredytHipoteczny {
int wyliczOplate() {
return 0.01 * wartosc;
}
}
class KredytSamochodowy {
int wyliczOplate() {
return 100 + 0.05 * wartosc;
}
}
class KredytKonsumpcyjny {
int wyliczOplate() {
return 300;
}
}
„Jeżeli do rozważenia jest tylko kilka możliwych wartości i nie spodziewasz się, że
pojawią się nowe to użycie polimorfizmu jest przesadą. ”
Zastąpienie użycia parametru przez wyspecjalizowane metody
Działanie pewnej metody całkowicie zależy od wartości przekazywanego parametru,
traktowanego jak wartość typu wyliczeniowego. Utwórz oddzielna metodę dla każdej
wartości parametru.”
class Kredyt{
int wyliczOplateDlaKredytuHipotecznego(){
return 0.01 * wartosc;
}
int wyliczOplateDlaKredytuSamochodowego(){
return 100 + 0.05 * wartosc;
}
int wyliczOplateDlaKredytuKonsumpcyjnego(){
return 300;
}
}
11. Równoległe hierarchie dziedziczenia [1]
„Równoległe hierarchie dziedziczenia stanowią szczególny przypadek poszatkowania.
Polega to na tym, że za każdym razem kiedy tworzy się podklasę pewnej klasy,; trzeba
też tworzyć podklasę pewnej innej klasy.”
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 10 z 39
08.09.2013 09:00
Możliwe rozwiązania:
- przemieszczenie metody lub przemieszczenie pola (pod warunkiem, że obiekty z jednej
hierarchii zawierają referencje do obiektów drugiej).
12. Leniwa klasa [1]
„Pielęgnacja każdej klasy kosztuje. Klasę, która na siebie nie zarabia, powinno się
usunąć.”
Możliwe rozwiązania:
- zwinięcie hierarchii (połączenie klasy z nadklasą),
- rozwinięcie klasy (usunięcie klasy po przemieszczeniu wszystkich jej elementów do
innej).
13. Spekulatywna ogólność [1]
„Brian Foote wymyślił te nazwę dla zapachu, na który jesteśmy niezwykle wyczuleni.
Czujesz go, kiedy ktoś mówi: 'Wydaje mi się, że kiedyś może to się przydać.' marzą mu
się rozmaite triki i bajery potrzebne do obsługi przypadków, które w istocie nie są
wymagane.”
Możliwe rozwiązania:
- zwinięcie hierarchii (klasy abstrakcyjne),
- rozwinięcie klasy (niepotrzebne delegowanie),
- usunięcie parametru (metody),
- zmiana nazwy metody (metody).
14. Pole tymczasowe [1]
„Zdarza się, że pewien obiekt zawiera zmienną egzemplarzową, której wartość jest
ustawiana jedynie czasami. (…) Próba zrozumienia, dlaczego jakaś zmienna istnieje,
skoro wydaje się nieużywana, może Cię doprowadzić do szału.”
Możliwe rozwiązania:
- „Użyj Wydzielenia klasy w celu utworzenia domu dla biednych osieroconych zmiennych.
Umieść w nowej klasie cały kod, który korzysta z tych zmiennych
”
15. Łańcuchy wywołań [1]
„Masz z nimi do czynienia, kiedy klient prosi jeden obiekt o referencje do innego
obiektu. Po czym pyta ten drugi obiekt o następny, a ten z kolei o jeszcze inny.”
Możliwe rozwiązania:
- ukrycie delegowania (utworzenie metod ukrywających delegata),
- wydzielenie metody i przemieszczenie metody.
16. Pośrednik [1]
„Przyglądasz się interfejsowi jakiejś klasy i okazuje się, że połowa metod deleguje
wywołania do jakiejś innej klasy.”
Możliwe rozwiązania:
- usunięcie pośrednika (zmiana kodu tak, by klient komunikował się bezpośrednio z
delegatem),
- rozwinięcia wywołań metody (zastąpieniu wywołania metody poprzez skopiowanie jej
ciała w miejscu jej wywołania
),
- zastąpienie delegowania przez dziedziczenie.
15. Zbytnia intymność [1]
„Czasami klasy są za bardzo ze sobą związane i zbytnio interesują się prywatnością
innych.”
Możliwe rozwiązania:
- przemieszczenie metody,
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 11 z 39
08.09.2013 09:00
-
przemieszczenie pola,
zmiana powiązania dwukierunkowego na jednokierunkowe,
wydzielenie klasy,
ukrycie delegowania,
zastąpienie dziedziczenia przez delegowanie.
16. Podobne klasy o różnych interfejsach [1]
Możliwe rozwiązania:
- zmiana nazwy metody,
- przemieszczanie metody,
- wydzielenie nadklasy.
17. Niepełne klasy biblioteczne [1]
Możliwe rozwiązania:
- utworzenie metody obcej,
- utworzenie lokalnego rozszerzenia.
Utworzenie metody obcej
„Pewnej klasy serwera, której kodu nie można niestety modyfikować przydałaby się nowa
metoda. Utwórz w klasie klienta metodę, której pierwszym argumentem jest obiekt klasy
serwera.”
Utworzenie lokalnego rozszerzenia
„W pewnej klasie serwera, której kodu nie można modyfikować, brakuje kilku przydatnych
metod. Utwórz nową klasę zawierającą te nowe metody. Nowa klasa będzie opakowaniem lub
podklasą klasy serwera.”
18. Odrzucony spadek [1]
„Podklasy dziedziczą po swoich rodzicach metody i dane. Co się jednak dzieje, jeżeli
ich nie chcą albo nie potrzebują.”
Możliwe rozwiązania:
- utworzenie nowej klasy oraz użycie przemieszczenia metody w dól i przemieszczenie
metody w górę,
- zastąpienie dziedziczenia przez delegowanie.
19. Komentarze [1]
„To zadziwiające, jak często widzi się kod suto opatrzony komentarzami i zdaje sobie
sprawę z tego, że są one tam dlatego, że kod jest źle napisany.”
Możliwe rozwiązania:
- wydzielenie metody,
- zmiana nazwy metody,
- dodanie asercji.
Dodanie asercji
Jeżeli komentarz opisuje pewne założenie na temat kodu, to zastosowanie asercji pozwoli
jawnie zapisać
to założenie.
public class Socket {
Server primary, secondary;
Object read() {
//the primary or the secondary server must be set
if (primary != null)
return primary.read();
else
return secondary.read();
}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 12 z 39
08.09.2013 09:00
public static void main(String[] args) {
Socket s = new Socket();
s.read();
}
}
public class Socket {
Server primary, secondary;
Object read() {
assert (primary != null || secondary != null) : "the primary and the secondary server
are ←֓
not set";
if (primary != null)
return primary.read();
else
return secondary.read();
}
public static void main(String[] args) {
Socket s = new Socket();
s.read();
}
}
20.
Klasy danych
”Klasy danych zawierają tylko pola, metody dostępu do nich i nic więcej. To bezmyślne
pojemniki na
dane i prawie na pewno inne klasy manipulują nimi w stopniu większym niż potrzeba.”
Możliwe rozwiązania:
• enkapsulacja pola dla pól publicznych,
• enkapsulacja kolekcji dla kolekcji,
• usunięcie metody ustawiającej, dla wszystkich pól, które powinny być tylko
odczytywane,
• przemieszczenie metody (patrz pkt. 2),
• wydzielenie metody i przemieszczenie metody (patrz pkt. 2),
• ukrycie metody dostępu.
MCcabe
Jedną z tradycyjnych miar produktów oprogramowania jest np. liczba wierszy kodu SLOC
(ang. Source Lines of Code).
Istnieje wiele wariantów dotyczących sposobu liczenia liczby wierszy kodu:
- zliczanie fizycznych wierszy kodu – prosta metoda pozwalająca zliczyć wszystkie
wiersze kodu, stosując
ten wariant należy zdecydować w jaki sposób potraktować komentarze oraz puste linie:
zliczać, nie
zliczać lub może zliczać tylko niektóre,
- zliczanie logicznych wierszy kodu – umożliwia zliczenie wykonywalnych wyrażeń
znajdujących się w kodzie.
Metryka: Złożoność cyklomatyczna McCabe’a
CC = E − N + 2 ∗ P
E – liczba krawędzi,
N – liczba węzłów,
P – liczba połączonych komponentów (węzłów wyjścia).
CC Złożoność oraz ryzyko związane z testowaniem oraz utrzymaniem kodu
1–10 prosty kod bez dużego ryzyka
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 13 z 39
08.09.2013 09:00
11–20 bardziej złożony kod o średnim ryzyku
21-50 złożony kod o wysokim ryzyku
51+ niestabilny kod o bardzo wysokim ryzyku
Metryki MIT zwane też metrykami C. K.
Weighted Method per Class (WMC)
„określająca metody ważone względem klasy, jest sumą złożoności statycznej klasy metod
jednej klasy.
Jeżeli przyjmie się, że złożoność każdej metody wynosi jeden, to metryka ta sprowadza
się po prostu do liczby
metod w klasie. ”
Depth of Inheritance Tree (DIT)
„określająca głębokość drzewa dziedziczenia”
Number of Childer (NOC)
„określająca liczbę potomków” (bezpośrednich)
Coupling Between Objects (CBO)
„określająca sprzężenie między obiektami, jest liczbą sprzężeń niezależnych od
struktury klasyfikacyjnej.
Nie rozróżnia asocjacji od relacji zespolenia czy używania – traktuje je wszystko jako
wysyłanie komunikatów.”
Dotyczy: typów atrybutów, parametrów, klauzul throws, typów zwracanych. Zazwyczaj
podczas obliczania
nie uwzględnia się: typów prymitywnych oraz klas z pakietu java.lang.
Response for Class (RFC)
„określająca reakcję na klasę, jest miarą strukturalnego sprzężenia klasy (. . . ).
Zlicza ona metody dostępne
w danej klasie albo bezpośrednio, albo za pośrednictwem komunikatu wysyłanego do
drugiej klasy (...).”
RFC = M + R
M – liczba metod w klasie,
R – liczba metod zdalnych (znajdujących się w innej klasie) wywołanych bezpośrednio
przez metody z tej klasy.
Lack of Cohesion of Methods (LCOM)
„określająca niespójność metod (. . . ). Mierzy ona nienakładanie się zbiorów
egzemplarzy zmiennych używanych przez metodę danej klasy. Istnieje jej alternatywna,
operacyjne definicja: procent metod, które nie
korzystają z atrybutów, osiągana średnio dla wszystkich atrybutów. Najniższa i
najbardziej pożądana wartość metryki LCOM występuje wtedy, kiedy wszystkie metody
używają wszystkich egzemplarzy zmiennych,
największa zaś wtedy, kiedy żadnego egzemplarza zmiennej nie używa więcej niż jedna
metoda.”
Dla każdej pary metod w klasie:
• jeżeli wykorzystują one rozłączne zbiory atrybutów to inkrementuj P,
• jeżeli wykorzystują one co najmniej jeden wspólny atrybut to inkrementuj Q.
if P > Q then
LCOM = P − Q
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 14 z 39
08.09.2013 09:00
else
LCOM = 0
end if
Metryki MOOD
- Attribute Hiding Factor (AHF),
- Method Hiding Factori (MHF),
- Attribute Inheritance Factor (AIF),
- Method Inheritance Factor (MIF),
- Polymorphism Factor (PF),
- Coupling Factor (CF).
Metryki R. Martina
W metrykach R. Martina jako kategorię należy rozumieć grupę klas: moduł, pakiet, itp.
Efferent Coupling (Ce)
Liczba klas wewnątrz kategorii, która zależy od klas na zewnątrz tej kategorii.
Afferent Coupling (Ca)
Liczba klas na zewnątrz kategorii, która zależą od klas należących do tej kategorii.
Instability (I)
I = 0 oznacza maksymalnie stabilna kategorię, natomiast I = 1 oznacza maksymalnie
niestabilną kategorię.
Abstractness (A)
Jest to stosunek abstrakcyjnych klas w kategorii do wszystkich klas w tej kategorii.
WZORCE PROJEKTOWE
Wzorce projektowe stanowią powtarzalne rozwiązanie zagadnień projektowych, z którymi
się
wciąż spotykamy
Wzorce projektowe:
Creational - dotyczą sposobu w jaki obiekty są tworzone. Obejmują wzorce:
- Singleton (Singleton),
- Pula Obiektów (Object Pool),
- Prosta Fabryka (Simple Factory),
- Metoda Wytwórcza (Factory
Method),
- Fabryka Abstrakcyjna (Abstract Factory),
- Prototyp (Prototype),
- Budowniczy (Builder),
Structural - dotyczą projektowania obiektów, tak aby spełniały ograniczenia nałożone na
projekt. Obejmują wzorce:
- Adapter (Adapter),
- Most (Bridge),
- Kompozyt (Composite),
- Fasada (Facade),
- Dekorator (Decorator),
- Pyłek (Flyweight),
- Pośrednik (Proxy)
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 15 z 39
08.09.2013 09:00
Behavioral - dotyczą obiektów, które wykonują zadane akcje. Obejmują wzorce:
- Odwiedzający
(Visitor),
- Iterator (Iterator),
- Obserwator (Observer),
- Stan (State),
- Strategia (Strategy),
- Metoda
Szablonowa (Template Method),
- Łańcuch Zobowiązań (Chain of Responsibility),
- Interpreter
(Interpreter),
- Polecenie (Command),
- Mediator (Mediator),
- Pamiątka (Memento).
Wzorzec Singleton jest stosowany w sytuacji, gdy dla danej klasy chcemy utworzyć tylko
jeden
obiekt.
public class Singleton {
private static Singleton s = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return s;
}
public void method(){}
}
public class TestSingleton {
public static void main(String[] args) {
Singleton s = Singleton.getInstance();
s.method();
}}
Object Pool - Najczęstsze zastosowania: pula połączeń, pula wątków.
Co
1.
2.
3.
zrobić w sytuacji, gdy nie ma wolnych obiektów:
Zgłosić informacje o błędzie do użytkownika (wyjątek, specjalna wartość).
Dodać nowy obiekt do puli (zazwyczaj pule mają ograniczony rozmiar).
Zablokować wątek aż obiekt będzie dostępny.
final public class Rental<V> {
private static class Entry<E> {
boolean used;
final E object;
Entry(E object) {
this.object = object;
}}
private int freePermits;
private int usedPermits;
final private Collection<Entry<V>> entries = new HashSet<Entry<V>>();
Rental(Collection<V> collection) {
if (collection == null)
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 16 z 39
08.09.2013 09:00
throw new NullPointerException();
for (V e : collection) {
if (e == null)
throw new NullPointerException();
entries.add(new Entry<V>(e));
}
freePermits = entries.size();
usedPermits = 0;
}
int getAvailable() {
return freePermits;
}
public synchronized V rent() {
if (freePermits > 0) {
--freePermits;
++usedPermits;
return getNext();
} else
return null;
}
private V getNext() {
for (Entry<V> e : entries)
if (!e.used) {
e.used = true;
return e.object;
}
return null;
}
public synchronized void giveBack(V object) {
if (tryReturn(object)) {
++freePermits;
--usedPermits;
}}
private boolean tryReturn(V c) {
for (Entry<V> e : entries)
if (e.object == c) {
if (!e.used)
return false;
e.used = false;
return true;
}
return false;
}}
Simple Factory
Polega na stworzeniu w klasie statycznej metody zwracającej obiekt jednej z możliwych
klas zależnie od dostarczonych danych. Różnice w stosunku do użycia konstruktora:
- można zwrócić obiekt klasy lub podklasy,
- można zwrócić obiekt już istniejący (bez tworzenia nowego),
- metodzie można nadać dowolną (opisową) nazwę.
abstract public class Figure {
abstract void draw();
public Figure getFigure(String name){
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 17 z 39
08.09.2013 09:00
if(name.equals("circle"))
return new Circle();
else if(name.equals("rectangle"))
return new Rectangle();
return null;
}
class Circle extends Figure{
…
}
class Rectangle extends Figure{
…
}
}
Factory Method
Wzorzec ten definiuje interfejs do tworzenia obiektów, ale wybór do jakiej klasy będzie
należał obiekt deleguje do podklasy.
Inna nazwa: Wirtualny Konstruktor.
interface NC {} //Network Connection
class CableNC implements NC {}
class WirelessNC implements NC {}
abstract class NSP { //Network Service Provider
protected abstract NC connect();
void doSomething(){
NC connection = connect();
//...
}
}
class CableNSP extends NSP {
protected NC connect() {
return new CableNC();
}
}
class WirelessNSP extends NSP {
protected NC connect() {
return new WirelessNC();
}
}
class Client {
public static void main(String arg[]) {
NSP [] providers = {new CableNSP(), new WirelessNSP()};
for(NSP p : providers)
p.doSomething();
}
}
Abstract Factory
Dostarcza interfejsu do tworzenia rodzin związanych ze sobą albo zależnych obiektów bez
podawania ich konkretnych klas. Abstrakcyjna fabryka może być traktowana jako fabryka
fabryk.
interface Frame {}
class DefaultFrame implements Frame {}
class MyFrame implements Frame {}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 18 z 39
08.09.2013 09:00
interface Menu {}
class DefaultMenu implements Menu {}
class MyMenu implements Menu {}
abstract class LAF { // LookAndFeel
protected abstract Frame createFrame();
protected abstract Menu createMenu();
}
class DefaultLAF extends LAF {
@Override
protected Frame createFrame() {
return new DefaultFrame();
}
@Override
protected Menu createMenu() {
return new DefaultMenu();
}
}
class MyLAF extends LAF {
@Override
protected Frame createFrame() {
return new MyFrame();
}
@Override
protected Menu createMenu() {
return new MyMenu();
}
}
class Runtime {
static private LAF laf = new DefaultLAF();
static LAF setLAF(String name) {
if (name.equals("MyLAF"))
laf = new MyLAF();
else if (name.equals("DefaultLAF"))
laf = new DefaultLAF();
return laf;
}
}
class Client {
public static void main(String arg[]) {
LAF laf = Runtime.setLAF("MyLAF");
Frame f = laf.createFrame();
Menu m = laf.createMenu();
}
}
Prototype
Umożliwia tworzenie obiektów na podstawie prototypowej instancji poprzez kopiowanie
prototypu.
class Prototype implements Cloneable{
static private Prototype instance = new Prototype();
class Prototype implements Cloneable{
static private Prototype instance = new Prototype();
private Prototype(){}
public static Prototype getPrototype(){
return instance;
http://localhost:8888/html/files/typy%20obiektowe.txt
…
Strona 19 z 39
08.09.2013 09:00
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
private int i = -1;
private Field f = new Field();
public void setI(int i) {
this.i = i;
}
@Override
public String toString(){
return super.toString() + " " + i + " " + f.toString();
}
}
class Field{}
public class Test {
public static void main(String arg[]) throws CloneNotSupportedException {
Prototype p = Prototype.getPrototype();
p.setI(1);
Prototype p2 = (Prototype) p.clone();
p.setI(2);
System.out.println(p);
System.out.println(p2);
}
}
Builder
Wzorzec ten pozwala na rozdzielenie konstrukcji złożonego obiektu od jego
reprezentacji.
class FrameBuilder {
private int x, y;
private int width, height;
private String title;
public void setPosition(int x, int y) {
this.x = x;
this.y = y;
}
public void setSize(int width, int height) {
this.width = width;
this.height = height;
}
public void setTitle(String title) {
this.title = title;
}
public Frame build() {
if (x != 0 && y != 0 && width != 0 && height != 0
&& title != null) {
JFrame f = new JFrame();
f.setSize(width, height);
f.setTitle(title);
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 20 z 39
08.09.2013 09:00
f.setLocation(x, y);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
return f;
}
return null;
}
}
public class TestBuilder {
public static void main(String[] args) {
FrameBuilder b = new FrameBuilder();
b.setSize(640, 480);
b.setPosition(100, 100);
b.setTitle("Test frame");
Frame f = b.build();
}
}
Adapter
Wzorzec ten ma za zadanie przekształcenie jednego interfejsu w drugi.
class EnumerationAdapter<E> implements Enumeration<E> {
private Iterator<E> i;
EnumerationAdapter(Iterator<E> i) {
this.i = i;
}
@Override
public boolean hasMoreElements() {
return i.hasNext();
}
@Override
public E nextElement() {
return i.next();
}
}
public class Adapter {
public static void main(String[] args) {
HashSet<Integer> s = new HashSet<Integer>(Arrays.asList(1,2,3));
// testEnumeration(s.iterator());
testEnumeration(new EnumerationAdapter<Integer>(s.iterator()));
}
public static void testEnumeration(Enumeration<?> e) {
while (e.hasMoreElements())
System.out.println(e.nextElement());
}
}
Bridge
Wzorzec mający na celu oddzielenie interfejsu od implementacji obiektu.
interface Storable {
public void add(int id, Object o);
public void update(int id, Object o);
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 21 z 39
08.09.2013 09:00
public Object get(int id);
public void delete(int id);
}
class Storage implements Storable {
private StorageMethod s;
public Storage(StorageMethod s) {
this.s = s;
}
@Override
public void add(int id, Object o) {
s.put(id, o);
}
@Override
public void update(int id, Object o) {
s.put(id, o);
}
@Override
public Object get(int id) {
return s.get(id, false);
}
@Override
public void delete(int id) {
s.get(id, true);
}
}
interface StorageMethod {
public void put(int id, Object o);
public Object get(int id, boolean delete);
}
class ArrayStorageMethod implements StorageMethod {
private Object[] a = new Object[1024];
public void put(int id, Object o) {
a[id] = o;
}
public Object get(int id, boolean delete) {
Object tmp = a[id];
if (delete)
a[id] = null;
return tmp;
}
}
class MapStorageMethod implements StorageMethod {
private HashMap<Integer, Object> m = new HashMap<Integer, Object>();
public void put(int id, Object o) {
m.put(id, o);
}
public Object get(int id, boolean delete) {
if (delete)
return m.remove(id);
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 22 z 39
08.09.2013 09:00
else
return m.get(id);
}
}
public class TestBridge {
public static void main(String[] args) {
Storage s = new Storage(new ArrayStorageMethod());
s.add(1, "TEST#1");
System.out.println(s.get(1));
s = new Storage(new MapStorageMethod());
s.add(2, "TEST#2");
System.out.println(s.get(2));
}
}
Composite
Umożliwia reprezentowanie złożonych struktur drzewiastych reprezentujących hierarchie
całość – część. Pozwala traktować zarówno pojedyncze obiekty jak i całe ich struktury w
taki sam sposób.
interface Element {
void list(String space);
}
class File implements Element {
String name;
File(String name) {
this.name = name;
}
public void list(String space) {
System.out.println(space + "File: " + name);
}
}
class Dir extends ArrayList<Element> implements Element {
String name;
public Dir(String name) {
this.name = name;
}
public void list(String space) {
System.out.println(space + "Dir: " + name);
Iterator<Element> i = iterator();
while (i.hasNext())
i.next().list(space + " ");
}
}
public class TestComposite {
public static void main(String[] args) {
Dir c1 = new Dir("C:");
c1.add(new File("autoexec.bat"));
c1.add(new File("boot.ini"));
Dir c2 = new Dir("Windows");
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 23 z 39
08.09.2013 09:00
c2.add(new File("notepad.exe"));
c1.add(c2);
c1.list("");
}
}
Facade
Wzorzec służy do zapewnia uproszczonego interfejs do skomplikowanego podsystemu.
Przykład: dostęp do bazy danych.
class Database {
private
private
private
private
private
Connection connection;
OracleDataSource dataSource;
CallableStatement proc;
Statement statement;
ResultSet resultSet;
public Database(URL url) {
connection = DriverManager.getConnection(url);
}
public static void execProcedure(String procedureName)
throws SQLException {
try {
proc = connection.prepareCall("BEGIN " + procedureName + ";
END;");
proc.execute();
} finally {
if (proc != null)
proc.close();
}
}
…
}
public class TestFacade {
public static void main(String[] args) throws MalformedURLException {
Database d = new Database(
new URL("jdbc:oracle:thin:user/password@host:port:database"));
d.execProcedure("test()")
…
}
}
Decorator
Wzorzec pozwala na zmianę właściwości poszczególnych obiektów bez potrzeby tworzenia
nowej klasy pochodnej.
interface Output{
void writeln(String s);
}
class StandardOutput implements Output {
public void writeln(String s){
System.out.println(s);
}
}
abstract class Decorator implements Output{
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 24 z 39
08.09.2013 09:00
protected Output output;
Decorator(Output output){
this.output = output;
}
}
class UpperOutput extends Decorator{
UpperOutput(Output output) {
super(output);
}
@Override
public void writeln(String s) {
output.writeln(s.toUpperCase());
}
}
class ReverseOutput extends Decorator{
ReverseOutput(Output output) {
super(output);
}
@Override
public void writeln(String s) {
output.writeln(new StringBuffer(s).reverse().toString());
}
}
public class TestDecorator {
public static void main(String[] args) {
Output output = new StandardOutput();
output.writeln("Ala ma kota Filemona");
output = new StandardOutput();
output = new UpperOutput(output);
output.writeln("Ala ma kota Filemona");
output = new StandardOutput();
output = new ReverseOutput(output);
output.writeln("Ala ma kota Filemona");
output = new StandardOutput();
output = new UpperOutput(output);
output = new ReverseOutput(output);
output.writeln("Ala ma kota Filemona");
}
}
Flyweight
Wzorzec pozwala zredukować liczbę małych obiektów reprezentujących dane.
Dwie metody przechowywania znaków dokumencie:
1. Dla każdego znaku w dokumencie przechowujemy jeden obiekt reprezentujący jego symbol
graficzny.
2. Dla każdego rodzaju znaku w dokumencie przechowujemy jeden obiekt reprezentujący
jego symbol graficzny oraz dodatkowo jego pozycje.
public class TestFlyweight {
public static void main(String[] args) {
String s1 = new String("TEST");
String s2 = new String("TEST");
System.out.println((s1 == s2));
String s3 = "TEST";
String s4 = "TEST";
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 25 z 39
08.09.2013 09:00
System.out.println((s3 == s4));
}
}
Proxy
Wzorzec ten jest wykorzystywany do reprezentowania jednego obiektu za pomocą drugiego.
Najczęstsze powody wykorzystywania tego wzorca:
- opóźnienie utworzenia obiektu,
- dostęp do obiektu znajdującego się na innej maszynie,
- ograniczenie praw dostępu do obiektu,
- konieczność wykonywania dodatkowych akcji podczas dostępu do obiektu.
Visitor
Wzorzec ten pozwala na dodawanie nowych operacji bez wprowadzania zmian do klas, na
których operuje.
interface GraphicComponent {
void accept(Visitor v);
}
interface Visitor {
void visit(Label b);
void visit(Button b);
void visit(Window b);
}
class Label implements GraphicComponent {
@Override
public void accept(Visitor v) {
v.visit(this);
}
public int getWidth() {
return 100;
}
}
class Button implements GraphicComponent {
@Override
public void accept(Visitor v) {
v.visit(this);
}
public int getBegin() {
return 0;
}
public int getEnd() {
return 200;
}
}
class SizeVisitor implements Visitor {
@Override
public void visit(Label b) {
System.out.println("Size = " + b.getWidth());
}
@Override
public void visit(Button b) {
System.out.println("Size = " + (b.getEnd() - b.getBegin()));
}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 26 z 39
08.09.2013 09:00
@Override
public void visit(Window b) {
System.out.println("Size = " + "???");
}
}
class NameVisitor implements Visitor {
@Override
public void visit(Label b) {
System.out.println("Name = " + b.getClass().getName());
}
@Override
public void visit(Button b) {
System.out.println("Name = " + b.getClass().getName());
}
@Override
public void visit(Window b) {
System.out.println("Name = " + b.getClass().getName());
}
}
class Window implements GraphicComponent {
GraphicComponent[] g = { new Button(), new Label() };
@Override
public void accept(Visitor v) {
for (GraphicComponent elem : g) {
elem.accept(v);
}
v.visit(this);
}
}
public class TestVisitor {
public static void main(String[] args) {
Window w = new Window();
w.accept(new SizeVisitor());
w.accept(new NameVisitor());
}
}
Iterator
Pozwala na sekwencyjny dostęp do obiektów znajdujących się w kolekcji bez ujawniania
jej szczegółów.
class IteratorImpl<E> implements Iterator<E>{
private E t[];
private int counter;
IteratorImpl(E t[]){
this.t = t;
counter = 0;
}
public boolean hasNext() {
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 27 z 39
08.09.2013 09:00
return counter < t.length;
}
public E next() {
return t[counter++];
}
public void remove() {
t[counter] = null;
}
}
class CollectionImpl<E> implements Collection<E>{
private E t[];
public CollectionImpl(E t[]){
this.t = t;
}
public boolean add(E e) {
throw new RuntimeException();
}
public boolean addAll(Collection<? extends E> c) {
throw new RuntimeException();
}
public void clear() {
throw new RuntimeException();
}
public boolean contains(Object o) {
throw new RuntimeException();
}
public boolean containsAll(Collection<?> c) {
throw new RuntimeException();
}
public boolean isEmpty() {
throw new RuntimeException();
}
public Iterator<E> iterator() {
return new IteratorImpl<E>(t);
}
public boolean remove(Object o) {
throw new RuntimeException();
}
public boolean removeAll(Collection<?> c) {
throw new RuntimeException();
}
public boolean retainAll(Collection<?> c) {
throw new RuntimeException();
}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 28 z 39
08.09.2013 09:00
public int size() {
throw new RuntimeException();
}
public Object[] toArray() {
throw new RuntimeException();
}
public <T> T[] toArray(T[] a) {
throw new RuntimeException();
}
}
public class TestIterator {
public static void main(String[] args) {
Integer t [] = {1,2,3};
CollectionImpl<Integer> c = new CollectionImpl<Integer>(t);
Iterator<Integer> i = c.iterator();
while(i.hasNext())
System.out.println(i.next());
}
}
Observer
Wzorzec ten jest wykorzystywany w sytuacji, gdy wybrane obiekty chcą być informowane o
zmianach stanu określonego obiektu.
interface Observer {
void update(Observable o, Object arg);
}
class Observable {
private Observer o;
public void addObserver(Observer o) {
this.o = o;
}
public void notifyObservers(Object object) {
o.update(this, object);
}
}
public class TestObserver {
public static void main(String[] args) {
Observable observable = new Observable();
observable.addObserver(new Observer(){
public void update(Observable o, Object arg) {
System.out.println("update " + arg);
}});
observable.notifyObservers("!!!");
}
}
State
Wzorzec ten służy do zmiany zachowania obiektu gdy zmianie ulegnie jego wewnętrzny
stan.
Na zewnątrz obiekt ten zachowuje się tak jakby należał do innej klasy.
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 29 z 39
08.09.2013 09:00
interface State{
public void click();
}
class Active implements State{
public void click() {
System.out.println("Action");
}
}
class NotActive implements State{
public void click() {
System.out.println("No action");
}
}
class Button{
private State s;
public Button(boolean active) {
setActive(active);
}
public void setActive(boolean active){
if(active)
s = new Active();
else
s = new NotActive();
}
public void click(){
s.click();
}
}
public class TestState {
public static void main(String[] args) {
Button c = new Button(true);
c.click();
c.setActive(false);
c.click();
c.setActive(true);
c.click();
}
}
Strategy
Wzorzec służy do definiowania grupy algorytmów, które mogą być stosowane wymiennie.
Posiadają one spólny interfejs a różnią się implementacją.
interface Sorter<E> {
public Collection<E> sort(Collection<E> e);
}
class QuickSort<E> implements Sorter<E> {
public Collection<E> sort(Collection<E> e) {
// ...
}
}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 30 z 39
08.09.2013 09:00
class BubbleSort<E> implements Sorter<E> {
public Collection<E> sort(Collection<E> e) {
// ...
}
}
public class Context<E> implements Sorter<E> {
private Sorter<E> s;
Context(Sorter<E> s) {
this.s = s;
}
public void changeSorter(Sorter<E> s) {
this.s = s;
}
public Collection<E> sort(Collection<E> e) {
return s.sort(e);
}
}
Template Method
Wzorzec ten stosowany jest do definiowania szkieletu algorytmu pozostawiając
jednocześnie
zdefiniowanie wybranych jego elementów w podklasach.
abstract class Sorter {
int[] data;
Sorter(int i) {
data = new int[i];
}
void execute() {
readData();
sort();
writeData();
}
void readData() {
System.out.println("Reading data");
}
abstract protected void sort();
void writeData() {
System.out.println("Writing data");
}
}
class QucickSort extends Sorter {
QucickSort(int i) {
super(i);
}
protected void sort() {
System.out.println("Sorting data");
}
}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 31 z 39
08.09.2013 09:00
public class TestTemplateMethod {
public static void main(String[] args) {
QucickSort s = new QucickSort(10);
s.execute();
}
}
Chain of Responsibility
Rozwala na luźne powiązanie pomiędzy nadawcą oraz odbiorcą, pozwala na przetwarzanie
żądania przez więcej niż jednego odbiorcę. Żądanie przekazywane jest przez łańcuch
odbiorców aż do momentu obsłużenia.
class Request {
private int i;
Request(int i){
this.i = i;
}
int getI(){
return i;
}
}
abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public void handleRequest(Request request) {
if (!handleRequestLoally(request)) {
if (nextHandler != null)
nextHandler.handleRequest(request);
else
throw new RuntimeException();
}
}
abstract protected boolean handleRequestLoally(Request request);
}
class MyHandler extends Handler {
private int divider;
MyHandler(int divider) {
this.divider = divider;
}
@Override
protected boolean handleRequestLoally(Request request) {
if (request.getI() % divider == 0) {
System.err.println("Request (" + request.getI()
+ ") handled (" + divider + ")");
return true;
} else {
System.err.println("Request (" + request.getI()
+ ") not handled (" + divider + ")");
return false;
}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 32 z 39
08.09.2013 09:00
}
}
public class Test {
public static void main(String[] args) {
Handler h2 = new MyHandler(2);
Handler h3 = new MyHandler(3);
Handler h5 = new MyHandler(5);
h2.setNextHandler(h3);
h3.setNextHandler(h5);
Request[] requests = { new Request(4), new Request(9),
new Request(25), new Request(1) };
for (Request r : requests)
h2.handleRequest(r);
}
}
Interpreter - służy do tworzenie interpretera języka o określonej gramatyce.
public class Context {
private String input;
private int output;
public Context(String input) {
this.input = input;
}
public String getInput() {
return input;
}
public void setInput(String input) {
this.input = input;
}
public int getOutput() {
return output;
}
public void setOutput(int output) {
this.output = output;
}
}
public abstract class Expression {
public void interpret(Context context) {
if (context.getInput().length() == 0)
return;
if (context.getInput().startsWith(nine())) {
context.setOutput(context.getOutput() + (9 * multiplier()));
context.setInput(context.getInput().substring(2));
} else if (context.getInput().startsWith(four())) {
context.setOutput(context.getOutput() + (4 * multiplier()));
context.setInput(context.getInput().substring(2));
} else if (context.getInput().startsWith(five())) {
context.setOutput(context.getOutput() + (5 * multiplier()));
context.setInput( context.getInput().substring(1));
}
while (context.getInput().startsWith(one())) {
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 33 z 39
08.09.2013 09:00
context.setOutput(context.getOutput() + (1 * multiplier()));
context.setInput(context.getInput().substring(1));
}
}
public
public
public
public
public
}
abstract
abstract
abstract
abstract
abstract
String one();
String four();
String five();
String nine();
int multiplier();
public
public
public
public
public
public
}
class ThousandExpression extends Expression{
String one() { return "M"; }
String four(){ return " "; }
String five(){ return " "; }
String nine(){ return " "; }
int multiplier() { return 1000; }
public
public
public
public
public
public
}
class HundredExpression extends Expression{
String one() { return "C"; }
String four(){ return "CD"; }
String five(){ return "D"; }
String nine(){ return "CM"; }
int multiplier() { return 100; }
public
public
public
public
public
public
}
class TenExpression extends Expression{
String one() { return "X"; }
String four(){ return "XL"; }
String five(){ return "L"; }
String nine(){ return "XC"; }
int multiplier() { return 10; }
public
public
public
public
public
public
}
class OneExpression extends Expression{
String one() { return "I"; }
String four(){ return "IV"; }
String five(){ return "V"; }
String nine(){ return "IX"; }
int multiplier() { return 1; }
public class MainInterpreter {
/**
* @param args
*/
public static void main(String[] args) {
String roman = "MCMXXVIII";
Context context = new Context(roman);
// Build the 'parse tree'
ArrayList<Expression> tree = new ArrayList<Expression>();
tree.add(new ThousandExpression());
tree.add(new HundredExpression());
tree.add(new TenExpression());
tree.add(new OneExpression());
// Interpret
for (Iterator it = tree.iterator(); it.hasNext();)
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 34 z 39
08.09.2013 09:00
{
Expression exp = (Expression)it.next();
exp.interpret(context);
}
System.out.println(roman + " = " +
Integer.toString(context.getOutput()));
}
}
Command - umożliwia traktowanie żądania jako obiektu, dzięki czemu możliwe jest ich
kolejkowanie,
logowanie, wycofywanie, itp.
interface Executable {
void execute();
}
class OneThreadExecutor {
private LinkedBlockingQueue<Executable> q;
OneThreadExecutor() {
q = new LinkedBlockingQueue<Executable>();
new Thread() {
@Override
public void run() {
try {
while (true)
q.take().execute();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
public void cancel(Executable task) {
q.remove(task);
}
public void execute(Executable task) {
q.add(task);
}
}
class MyExecutable implements Executable{
private int time;
private String text;
MyExecutable(int time, String text){
this.time = time;
this.text = text;
}
@Override
public void execute() {
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 35 z 39
08.09.2013 09:00
e.printStackTrace();
}
System.out.println(text);
}
}
public class TestCommand {
public static void main(String[] args) {
OneThreadExecutor e = new OneThreadExecutor();
MyExecutable longTask = new MyExecutable(3, "Long task");
MyExecutable shortTask = new MyExecutable(1, "Short task");
MyExecutable veryLongTask = new MyExecutable(5, "Very long task");
e.execute(longTask);
e.execute(shortTask);
e.execute(veryLongTask);
e.cancel(shortTask);
}
}
Mediator Definiuje obiekt, który ukrywa sposób interakcji pomiędzy grupą obiektów.
Umożliwia tworzenie luźnych powiązań pomiędzy obiektami poprzez umożliwienie usunięcia
przechowywania referencji bezpośrednio.
class Person {
private String firstName;
private String lastName;
protected Chat chat;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public void register(Chat chat) {
this.chat = chat;
}
@Override
public String toString() {
return firstName + " " + lastName;
}
}
class Student extends Person {
private String group;
public Student(String firstName, String lastName, String group) {
super(firstName, lastName);
this.group = group;
}
public String getGroup() {
return group;
}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 36 z 39
08.09.2013 09:00
public void send(String text) {
chat.send(this, text);
}
}
class Teacher extends Person {
private String specialization;
public Teacher(String firstName, String lastName, String specialization){
super(firstName, lastName);
this.specialization = specialization;
}
public String getSpecialization() {
return specialization;
}
public void send(String text) {
chat.send(this, text);
}
}
class Chat {
private HashSet<Teacher> teacher = new HashSet<Teacher>();
private HashMap<String, HashSet<Student>> students =
new HashMap<String, HashSet<Student>>();
public void register(Student s) {
HashSet<Student> group = students.get(s.getGroup());
if (group == null) {
group = new HashSet<Student>();
students.put(s.getGroup(), group);
}
group.add(s);
s.register(this);
}
public void register(Teacher t) {
teacher.add(t);
t.register(this);
}
public void send(Student s, String m) {
HashSet<Student> group = students.get(s.getGroup());
for (Student tmp : group) {
if (s != tmp)
System.out.println(
"Student " + s + " sends " + m + " to " + tmp);
}
}
public void send(Teacher t, String m) {
for (HashSet<Student> group : students.values())
for (Student tmp : group) {
System.out.println(
"Teacher "+ t + " sends " + m + " to " + tmp);
}
}
}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 37 z 39
08.09.2013 09:00
public class TestChatRoom {
public static void main(String[] args) {
Chat c = new Chat();
Student sA = new Student("AAA", "AAA", "1");
c.register(sA);
Student sB = new Student("BBB", "BBB", "1");
c.register(sB);
Student sC = new Student("CCC", "CCC", "1");
c.register(sC);
Student sX = new Student("XXX", "XXX", "2");
c.register(sX);
Student sY = new Student("YYY", "YYY", "2");
c.register(sY);
Student sZ = new Student("ZZZ", "ZZZ", "2");
c.register(sZ);
Teacher t = new Teacher("TTT", "TTT", "Computer science");
c.register(t);
sA.send("Hello");
sX.send("Hello");
t.send("Hello");
}
}
Memento Wzorzec ten, nie naruszając hermetyzacji, pozwala na zapis stanu obiektu tak
aby obiekt mógł powrócić do tego stanu. Pozwala to na realizację „punktów kontrolnych”
oraz przywrócenia poprzedniego stanu obiektu.
Wzorzec ten definiuje trzy podstawowe role [1]:
- Originator (Sprawca) – obiekt, którego stan chcemy zapisywać,
- Memento – obiekt, który zapisuje stan,
- Caretaker (Dozorca) – zarządza zapisem stanu, zapisuje Memento i używa go, gdy jest
potrzebny do przywrócenia stanu.
Memento powinien posiadać dwa interfejsy:
- używany przez Caretaker, pozwala tylko na przekazanie obiektu Memento do innego
obiektu,
- używany przez Originator, pozwalający przywrócić poprzedni stan obiektu,
class Originator {
private int state;
public void incState() {
state++;
}
public Memento createMemento() {
return new Memento(state);
}
public void setMemento(Memento m) {
this.state = m.state;
}
@Override
public String toString(){
return super.toString() + " " + state;
}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 38 z 39
08.09.2013 09:00
static class Memento {
private int state;
Memento(int state) {
this.state = state;
}
}
}
class Caretaker {
private Originator.Memento memento;
public Originator.Memento getMemento() {
return memento;
}
public void setMemento(Originator.Memento memento) {
this.memento = memento;
}
}
public class TestMemento {
public static void main(String[] args) {
Originator o = new Originator();
o.incState();
System.out.println(o);
Caretaker c = new Caretaker();
Originator.Memento oldState = o.createMemento();
c.setMemento(oldState);
o.incState();
System.out.println(o);
o.setMemento(c.getMemento());
System.out.println(o);
}
}
http://localhost:8888/html/files/typy%20obiektowe.txt
Strona 39 z 39

Podobne dokumenty