35
Funkcje i klasy zaprzyjaznione
1. Funkcje zewnętrzne zaprzyjaznione z klasą
Przykład:
#include
#include
class STRING
{ string str;
friend void DrukujStr( STRING &);
friend void UsunStr( STRING &);
// powyżej deklaracje zaprzyjaznienia funkcji zewnętrznych
// z klasą STRING
public:
STRING(void): str(0) { }
STRING(char *s): str(strdup(s)) { } // konstruktor kopiujący
~STRING(void) { delete [ ] str; }
// powyżej destryktor sprzątający po sobie
};
// poniżej definicje funkcji zewnętrznych
void DrukujStr( STRING & s)
{ cout<< \n <void UsunStr( STRING & s)
{ delete [ ] s.str;}
main( )
{ STRING Imie( Jan ), Nazwisko( Nowak );
DrukujStr(Imie); UsunStr(Nazwisko);
return 0;
};
35
36
o Funkcja zaprzyjazniona uzyskuje dostęp do składowych
prywatnych i chronionych obiektów klasy, z którą jest
zaprzyjazniona.
o Usunięcie jej deklaracji znosi zaprzyjaznienie.
o Nie ma znaczenia, w której sekcji definicji klasy
umieścimy deklaracje funkcji zaprzyjaznionych.
o Funkcja zaprzyjazniona nie posiada wskaznika this.
o Identyfikator funkcji zaprzyjaznionej może kolidować z
nazwami składowych klasy.
o Funkcje zaprzyjaznione bywają używane (powiedzmy
szczerze: nadużywane) jako funkcje interfejsu klas.
o Nieco lepszym rozwiązaniem jest tworzenie własnych
interfejsowych klas, zawierających wyłącznie funkcje
zaprzyjaznione z klasą, do której tworzymy interfejs, lub
klas interfejsowych pochodnych bez funkcji
zaprzyjaznionych.
o Nadużywanie funkcji zaprzyjaznionych powinno być
karane .
2. Funkcje składowe klasy zaprzyjaznione z inną klasą
class X class Y
{ . . . . . . . { . . . . . . .
void f( ); friend void X:: f( );
}; };
Funkcja X:: f( ) ma dostęp zarówno do własnych składowych
(tzn. obiektu klasy X), jak i wszystkich składowych klasy Y,
co pozwala jej bezpośrednio operować na składowych klasy Y
bez potrzeby wywoływania funkcji klasy Y (zaprzeczenie idei
hermetyzacji).
36
37
3. Zaprzyjaznione jednej klasy z inną klasą
class X class Y
{ . . . . . . . { . . . . . . .
void f( ); friend class X;
}; };
Powiemy, że klasa X jest zaprzyjazniona z klasą Y. Teraz
wszystkie funkcje składowe klasy X mają dostęp do
wszystkich składowych klasy Y, ale nie odwrotnie .
Przykład tworzenia klasy interfejsowej, opartej na funkcjach
zaprzyjaznionych:
#include
#include
class INTERFEJS_STRING; // deklaracja zapowiadająca
class STRING
{ string str;
public:
STRING(string s = ): str(strdup(s)) { }
friend class INTERFEJS_STRING;
};
class INTERFEJS_STRING
{ public:
void OutStr( STRING &s)
{ cout<< \n <};
37
38
main( )
{ STRING S( Ala ma kota );
INTERFEJS_STRING interf1;
interf1.OutStr(S);
return 0;
};
Zagnieżdżenie definicji klas
class LISTA
{
struct ELEM
{ int klucz;
ELEM *next;
// poniżej niepełny konstruktor struktury
ELEM( int k, ELEM * ptr;)
{ klucz = k; next = ptr; }
}; // definicja klasy zagnieżdżona
ELEM * head; // dana składowa klasy LISTA
public:
LISTA( ) { head = 0; }
void wstaw( int k){ head = new ( ELEM(k, head));}
};
Definicja klasy ELEM jest wyłączną własnością klasy LISTA
zapożyczenie z paradygmatu strukturalnego.
38
39
Wzorce (szablony) funkcji i klas
1. Wzorce funkcji zewnętrznych
Przykład wzorca funkcji:
template < class T >
T min( T x, T y )
{
return x>y ? y : x ;
}
Kompilator może wygenerować z powyższego wzorca funkcję
zewnętrzną dla tych typów T, dla których jest określony
operator >.
Na przykład, dopiero po napotkaniu wywołania min(a,b),
gdzie a i b są typu int, wzorzec funkcji zostanie
skompilowany i wygenerowana funkcja o nagłówku
int min( int, int ).
2. Wzorce klas
(synonimy: szablony klas, klasy zbiorcze, klasy
sparametryzowane)
Przykład wzorca klas obsługujących stos obiektów dowolnego
typu:
rozm
p
v
39
40
template < class T > ( 1)
class STOS
{
T *v; T *p; int rozm;
public:
STOS( int r) {v = p = new T[ rozm = r ]; }
<"STOS( ) { delete [ ] v; }
void włóż( T a ) { *p++ = a; }
T zdejmij( ) { return *--p ; }
int rozmiar( ) const {return p v; }
};
T jest pewnym typem, lub oznacznikiem klasy.
Zasięg T rozciąga się od (1) do końca deklaracji klasy.
Przykłady użycia:
STOS< char > sc(100);
// definicja obiektu klasy stos znaków
STOS< PUNKT> sp(10);
// definicja obiektu klasy stos obiektów klasy PUNKT
STOS< FIGURA * > spf(200);
// definicja stosu wskazań do obiektów klasy FIGURA
STOS< int> *p; // wskaznik do stosu liczb całkowitych
p = new STOS(800);
// dynamiczne tworzenie stosu liczb całkowitych
40
41
Niech:
struct COMPLEX
{ double re, im;
COMPLEX( double r, double i ): re(r), im(i) {}
};
wtedy:
void f( STOS< COMPLEX > & s );
// deklaracja funkcji o parametrze typu referencja do
// stosu obiektów klasy COMPLEX
s . włóż( COMPLEX( 1, 2 ) );
COMPLEX z = 2,5 * s . zdejmij( );
// przykłady wyrażeń, które mogłyby się znalezć we
// wnętrzu funkcji f( ), gdyby zdefiniowano operator *
// dla klasy COMPLEX
Definiowanie wzorców funkcji składowych
Funkcje składowe wzorca ( w tym konstruktory i destruktory )
można definiować na zewnątrz jego definicji, np.:
template < class T > void STOS< T >:: włóż( T a)
{ * p++ = a ; } // metoda wzorca klasy
template < class T > STOS< T >:: STOS( int r)
{ v = p = new T[ rozm = r ]; } // konstruktor
To kompilator, a nie programista, wygeneruje odpowiednią
definicję klasy i wszystkie jej składowe. Będą one
umieszczone w kodzie konkretnego programu jako zwykłe
definicje.
41
42
o Wzorce powinny być w bardzo małym stopniu
uzależnione od globalnej informacji, gdyż mogą być
używane dla nieznanych typów i w nieznanych
kontekstach,
o Wzorzec powinien posiadać domyślny (bezpara-
metrowy) konstruktor, ponieważ kompilator nie ge-
neruje konstruktorów domyślnych dla typów, które nie są
predefiniowane.
Wygodnie jest używać definicji typów, np.:
typedef STOS< char > STOS_ZNAKOW;
teraz można już deklarować: STOS_ZNAKOW sc(800);
Modelowanie obiektowe
Modelowanie obiektowe jest złożonym procesem, którego
celem jest zbudowanie pewnego modelu rzeczywistości w
określonej wcześniej dziedzinie problemu, widzianej przez
pryzmat przyjętych obowiązków budowanego systemu
informatycznego.
Każdy model jest uproszczeniem rzeczywistości (ma
określony poziom szczegółowości i ukierunkowanie).
Modele opracowujemy po to, aby lepiej zrozumieć
system, który budujemy.
Modelowanie obiektowe umożliwia wyspecyfikowanie
struktury i zachowania przyszłego systemu.
Modele stanowią dokumentację podjętych przez nas
decyzji.
Modele złożonych systemów budujemy dlatego, że nie
jesteśmy w stanie ogarnąć tych systemów w całości.
42
43
Wybór rodzaju modelu ma wielki wpływ na sposób
przebiegu całego przedsięwzięcia a także kształt
ostatecznego rozwiązania.
Żaden jeden model nie jest wystarczający. Kilka
dopełniających się, powiązanych ze sobą modeli,
obejmujących różne perspektywy systemu, to najlepsze
rozwiązanie w przypadku każdego niebanalnego systemu.
Praktycznie budowa takiego modelu sprowadza się do
stworzenia szeregu diagramów, które pozwalają opisać:
wymagania stawiane przez użytkowników systemu
(diagram przypadków użycia),
strukturę statyczną klas i obiektów (diagram klas,
diagram obiektów),
przepływ sterowania w systemie (diagram przebiegu,
diagram kooperacji, diagram stanów, diagram czynności)
przepływy danych.
Wszystkie te diagramy (a także inne, związane z wdrożeniem
systemu) tworzymy korzystając z języka UML (ang. Unified
Modeling Language), który jest standardem w dziedzinie
modelowania obiektowego.
Modelowanie przypadków użycia systemu
Diagram przypadków użycia systemu pełni pierwszą i
podstawową rolę w projektowaniu systemu a także
planowaniu jego powstawania.
Podstawowe definicje:
Przypadek użycia systemu jest zbiorem scenariuszy,
powiązanych ze sobą wspólnym celem użytkownika (aktora).
43
44
Scenariusz jest ciągiem kroków opisujących interakcję
między aktorem a modelowanym systemem.
Aktor (rola) jest to funkcja, którą użytkownik pełni w
stosunku do systemu.
Zakup towaru
1. Klient przegląda katalog i wybiera towar
2. Klient przechodzi do kasy
3. Klient podaje adres i termin dostawy
4. System podaje pełną informację cenową
5. Klient podaje informacje o karcie kredytowej
6. System autoryzuje sprzedaż
7. System wysyła e-mail do klienta z potwierdzeniem
transakcji
Alternatywa: niepowodzenie autoryzacji w kroku 6.
Umożliwić klientowi powtórzenie kroku 5. i przejść do
kroku 6.
Alternatywa: stały klient
Wg. scenariusza głównego do punktu 2
3. System wyświetla: bieżące warunki dostawy,
informacje o cenie, cztery ostatnie cyfry numeru karty
kredytowej
4. Klient potwierdza, lub zmienia swoje dane domyślne
Wg. scenariusza głównego od punktu 6
Przykład scenariusza zakupu towaru w sklepie internetowym
44
45
Ustal
limity
Zaktualizuj
rachunki
System
księgowy
Przeanalizuj
<>
ryzyko
Określ
wartość
Wyceń
<>
kontrakt
Aktor
Makler
Zarejestruj
transakcję
Uogólnienie
Sprzedawca
Limit
przekroczony
Przypadek
użycia
Diagram przypadków użycia dla systemu maklerskiego
Zalecenie metodologiczne:
" W scenariuszach i diagramie przypadków użycia nie
należy dokumentować zbyt wielu szczegółów. Im wyższy
stopień ryzyka niesionego przez przypadek użycia, tym
dokładniejszy powinien być scenariusz. W dalszym
procesie iteracyjnym i przyrostowym tworzenia systemu
uszczegóławia się poszczególne scenariusze.
45
46
Modelowanie związków między aktorami a przypadkami
użycia:
1. Aktor to pełniona rola, a nie osoba fizyczna,
zajmowane stanowisko, lub konkretny system ta
sama osoba może móc pełnić rolę kierownika sali,
maklera i sprzedawcy. Odwrotnie może być wiele
osób pełniących rolę maklera.
2. Jeden aktor może występować w wielu przypadkach
użycia i na odwrót przypadek użycia może być
wykonywany przez wielu aktorów.
3. Należy dążyć do wykrycia wszystkich przypadków
użycia systemu.
4. Mogą być przypadki użycia nie mające związków z
konkretnymi aktorami.
5. Najważniejszym jest zrozumienie przypadku użycia
i celów użytkownika, które spełnia.
Modelowanie związków między poszczególnymi przypadkami
użycia:
1. Do relacji zawierania dochodzi wtedy, gdy kilka
przypadków użycia ma wspólną sekwencje podobnych
kroków w scenariuszu.
2. Uogólnienie jest jak gdyby dziedziczeniem na poziomie
przypadków użycia. Przypadek użycia podrzędny (zwany
niekiedy specjalistycznym przypadkiem użycia) zwykle
zawiera jeden ze scenariuszy alternatywnych
podstawowego (uogólnionego) przypadku użycia.
Chociaż specjalistyczny przypadek użycia przesłania
niekiedy część podstawowego przypadku użycia, ale
zawsze powinien dotyczyć tego samego celu
użytkownika, co podstawowy przypadek użycia.
46
47
Zalecenie metodologiczne:
1. Gdy trzeba powtórzyć coś w kilku różnych przypadkach
użycia, a jednocześnie chce się uniknąć powtórzeń, należy
używać relacji zawierania.
2. Gdy trzeba opisać warianty typowego postępowania przy
niezbyt jeszcze sformalizowanym scenariuszu, należy
używać relacji uogólnienia.
3. Rozbicie podstawowego przypadku użycia przy użyciu
uogólnień i rozszerzeń powinno mieć rozsądny stopień,
adekwatny do przyjętego w całym diagramie przypadków
użycia, stopnia szczegółowości.
Biznesowe i systemowe przypadki użycia
Systemowy przypadek użycia to interakcja użytkownika (lub
innego systemu) z danym systemem, biznesowy przypadek
użycia to reakcja przedsiębiorstwa (a nie systemu) na klientów
i zdarzenia zewnętrzne. We wczesnych fazach rozwinięcia
systemu należy koncentrować się bardziej na biznesowych
przypadkach użycia. Pomagają one, na przykład, w
wypracowaniu alternatywnych sposobów osiągnięcia celu
przez aktora. Pózniej dopiero można wypracowywać,
spełniające poszczególne biznesowe przypadki użycia,
systemowe przypadki użycia. Te ostatnie są niezbędne dla
dalszego rozwijania systemu, począwszy od pierwszego jego
prototypu.
Posumowanie:
" Przypadki użycia są podstawowym narzędziem w
uchwyceniu wymagań systemu a pózniej w planowaniu i
zarządzaniu iteracyjnym projektem tworzenia systemu
informatycznego, zwłaszcza w metodologii
programowania ekstremalnego.
47
48
" Każdy przypadek użycia to potencjalne wymaganie, a
dopóki nie określi się wymagań, nie można zaplanować
co dalej .
" Większość przypadków użycia powstaje w fazie projektu,
ale w miarę postępu prac pojawiają się nowe.
" Przypadki użycia reprezentują spojrzenie z zewnątrz na
tworzony system i dlatego nie istnieją korelacje między
nimi a klasami wewnątrz systemu.
" Modelowanie pojęciowe (poprzez biznesowe przypadki
użycia) to najlepsza platforma porozumienia z przyszłym
użytkownikiem tworzonego systemu informatycznego.
Model statyczny. Diagram klas
Diagram klas w perspektywie pojęciowej obrazuje:
klasy modelowanego systemu,
związki (asocjacje) miedzy nimi.
W perspektywie implementacyjnej diagram ten zwykle ulega
zmianom (rozszerzeniu o nowe klasy i asocjacje).
Narzędzia implementujące język UML (np. Rational Rose)
pozwalają oglądać diagram klas na różnym poziomie
szczegółowości. Dlatego mówimy o:
warstwie klas i powiązań,
warstwie atrybutów i usług, oraz
warstwie specyfikacyjnej.
Rysunek na stronie 49 prezentuje przykładowy fragment
diagramu klas modelującego przypadek użycia Zamawianie
towaru przedstawiony w warstwie atrybutów i usług.
48
49
nawigowalność
Zamówienie asocjacja
dataOtrzymania Klient
przedpłata
nazwa
numer : String
adres
cena : waluta
*
*
wiarygonośćKredytowa() : String
wyślij()
zamknij()
krotność
klientFirmowy
klientIndywidualny
{jeśli
osobaDoKontaktów
numerKartyKredytowej
zamowienie.klient.wiarygodnośćKredyto
wiarygodnośćKredytowa
wa jest "niska" to
limitKredytowy
zamowienie.przedpłata musi być
prawdziwe}
wiarygodnośćKredytow
przypomnij()
a jest "niska"}
obciążZaMiesiąc()
ograniczenie
0..*
0..*
ograniczenie
nazwa
przedstawiciel handlowy
roli
pozycje
0..*
0..*
Pracownik
pozycjaZamówienia
ilość : Integer
towar
cena : waluta
0..*
zapewniona : Boolean0..*
Niektóre klasy na tym rysunku zostały przedstawione
skrótowo, tak jak się to robi tworząc warstwę klas i powiązań.
Są to klasy Towar i Pracownik. Pozostałe klasy zostały
wyspecyfikowane w sposób typowy dla warstwy atrybutów i
usług, kiedy to podaje się tylko najważniejsze dla zrozumienia
modelu i ważne z punktu widzenia modelowanego przypadku
użycia, atrybuty i usługi. Typ wartości atrybutu, lub wartości
zwracanej przez usługę, zwykle nie jest specyfikowany, chyba
że jest to istotne dla zrozumienia modelu. Nie podaje się też
argumentów usług i ich typów.
Natomiast w warstwie specyfikacyjnej podaje się pełną
specyfikację atrybutów, wg. schematu
specyfikatorDostępu nazwaAtrybutu:typ=wartość_domyślna
49
50
oraz specyfikacje usług wg. schematu
specyfikatorDostępu nazwaUsługi(lista_parametrów):
typ_wyniku {łańcuch_własności}
Asocjacje (powiązania)
W perspektywie pojęciowej asocjacje reprezentują stałe
związki pojęciowe miedzy obiektami klas:
Klient firmowy jest rodzajem Klienta (dziedziczenie),
Zamówienie jest tworzone przez Klienta (pojedynczego,
chociaż Klient może złożyć kilka Zamówień),
Klient firmowy może mieć Pracownika w roli
Przedstawiciela handlowego (co najwyżej jednego).
Przedstawienie ról wygląda ogólnie tak jak na poniższym
rysunku
rola B
Klasa A
Klasa B
rola A
Nazwy ról można pominąć, jeśli pełnione role są oczywiste i
zrozumiałe.
Z punktu widzenia perspektywy implementacyjnej asocjacje
oznaczają zobowiązania klas i muszą znalezć swoje odbicie w
usługach klas i strukturze bazy danych, obsługiwanej przez
obiekty obu klas.
Zobowiązania, o których powyżej, są czasem przedstawiane
za pomocą strzałek
* 1
Mówimy wtedy, że mamy do czynienia z nawigowalnością,
lub asocjacją jednokierunkową, czyli o możliwości przejścia
z klasy do klasy. Realizowane jest to w ten sposób, że np.
50
51
obiekt klasy A ma wskaznik do obiektu klasy B (mówimy
czasem, że posiada obiekt klasy B), ale nie odwrotnie.
Nawigowalność powinna być specyfikowana w perspektywie
implementacyjnej, natomiast w perspektywie pojęciowej nie
musi.
Stosowanie ograniczeń
Ograniczenia, specyfikowane jako {opis ograniczenia}
dotyczą klas. Są to asercje, które są zdaniami logicznymi
zawsze (dla wszystkich obiektów klas) prawdziwymi.
Wpisanie ograniczenia do diagramu klas zobowiązuje
implementującego do takiego napisania kodu, aby
prawdziwość ograniczenia była zawsze zapewniona.
Końcowe uwagi metodologiczne, dotyczące diagramów klas:
1. Na etapie budowy modelu analizy należy stosować tylko
perspektywę pojęciową.
2. Na początek używać tylko omawianych powyżej
elementów: klas, asocjacji, istotnych dla zrozumienia
modelu atrybutów i usług, ról, krotności obiektów,
uogólnień i ograniczeń.
3. Pózniej, ale tylko gdy będzie wyrazna potrzeba, można
wprowadzać bardziej złożone elementy: nawigowalność,
agregację, zawieranie, role uporządkowane, asocjacje
kwalifikowane, powiązania w postaci zależności.
4. Lepiej jest mieć diagramy klas dla poszczególnych
przypadków użycia systemu (nawet z pewnymi częściami
wspólnymi), niż jeden wielki diagram, modelujący cały
system, gdyż:
- pozwala to użytkownikowi lepiej zrozumieć
system,
- ułatwia modyfikację (dodawanie funkcjonalności) i
kontrolę poprawności modelu.
51
52
5. Na każdym etapie należy uważać, aby nie ugrzęznąć w
szczegółach.
Koniec części III
52
Wyszukiwarka
Podobne podstrony:
Jezyki i paradygmaty cz II
Jezyki i paradygmaty cz IV
Jezyki i paradygmaty cz V
Języki i paradygmaty zaocz cz I
LIMS system zarządzania działalnością laboratorium Cz III Uprawnienia i rozwiązania indywidualne
Algorytmy i złożoność cz III
Problemy bohaterów Dziadów cz III i Wesela wobec proble~963
o Wstęp do cz III Czy myślimy matematycznie
Prawo rzymskie cz III prawo osobowe z czynnościami prawnymi
kurs od marzenia do sukcesu cz iii
BO IIIsem MNied cz III
cz III Udzial spoleczenstwa
więcej podobnych podstron