Zakład Inżynierii Oprogramowania

Transkrypt

Zakład Inżynierii Oprogramowania
Zakład Inżynierii Oprogramowania
Programowanie w języku Java
WYKŁAD
dr inż. Piotr Zabawa
Certyfikowany Konsultant IBM/Rational
e-mail: [email protected]
www:
http://www.pk.edu.pl/~pzabawa
24.02.2014
Zakład Inżynierii Oprogramowania
WYKŁAD 1
Wzorce projektowe
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Znaczenie wzorców projektowych
•
•
•
•
Podstawowe biblioteki Java oparte są o wzorce projektowe – widać je
od strony programisty Java
Wzorce projektowe są podstawową dobrą praktyką programistyczną w
językach obiektowych
Samodzielne stosowanie wzorców projektowych pozwala na:
– Uodpornienie kodu na zmiany (gł. związane z iteracyjnością
procesu wytwórczego)
– Zwiększenie ponownego użycia przez osłabienie relacji
– Prawidłowe uchwycenie podziału odpowiedzialności (wspiera
kryterium jakości programowania obiektowego weak coupling &
strong cohesion)
Pozwala wprowadzić podstawowe pojęcia z UML
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Czym są wzorce projektowe
•
•
•
Są to ustandaryzowane rozwiązania często spotykanych problemów
projektowych o niewielkim zasięgu w kodzie (zwykle obejmują kilka
klas)
Dzięki nim nie trzeba odkrywać za każdym razem na nowo tych
rozwiązań
W inżynierii oprogramowania wyróżnia się szereg wzorców:
– Projektowe
– Architektoniczne
– Korporacyjne
– Przypadków użycia
– Analityczne
– Testowe…
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorce projektowe a Java
W każdym języku programowania wzorce mogą mieć różne realizacje.
W języku Java:
• Interfejsy
• Klasy abstrakcyjne
• Klasy wewnętrzne, w tym anonimowe klasy wewnętrzne
Dodatkowo potrzebna jest znajomość podstawowych mechanizmów
wspierających obiektowość:
• Abstrakcja
• Enkapsulacja
• Dziedziczenie
• Polimorfizm
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Model UML a Java
Nie ma bezpośredniego związku między pojęciami UML a
mechanizmami dostępnymi w językach programowania. Model wyraża
koncepcje, które trzeba obsługiwać ręcznie w kodzie. To samo dotyczy
Javy.
Zrobić rysunki relacji i kodu ręcznie na tablicy.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Model UML a Java - generalizacja
Relacja generalizacji znana z UML (dotyczy nie tylko pojęcia klasy i
interfejsu) jako generalizacja ma swoje ucieleśnienie w obiektowych
językach programowania w postaci relacji dziedziczenia. Pojęcia te są
zbieżne.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Model UML a Java
class A1 {}
classs B1 extends A1 {}
Jest to relacja najsilniej wiążąca ze sobą klasy, a więc najbardziej
utrudniająca wprowadzanie zmian. Zmiany te mają tendencję do
propagowania się w hierarchii dziedziczenia. Wzorce projektowe
ograniczają negatywne skutki wprowadzania hierarchii dziedziczenia do
kodu źródłowego poprzez zmianę podziału odpowiedzialności.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Model UML a Java – relacje
asocjacyjne
Jest to zbiór relacji wiążących ze sobą obiekty czasem życia. Obejmuje
trzy relacje:
• Kompozycję
• Agregację
• Asocjację
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Model UML a Java
class A2 {
class B2 {}
}
Relacja kompozycji wiąże ze sobą obiekty czasem życia w sposób bardzo
silny. Jeśli obiekt nadrzędny zostanie usunięty, to automatycznie musi
zostać usunięty obiekt podrzędny. Obiekt podrzędny jest widoczny tylko z
obiektu nadrzędnego, więc nie może być uwikłany w inne relacje
asocjacyjne.
Rzadko spotykana we wzorcach projektowych ze względu na zbyt silne
wiązanie ze sobą obiektów.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Model UML a Java
class B3 {}
class A3 {
B3 b3;
}
Relacja agregacji jest słabsza od relacji kompozycji. Wiąże ze sobą
obiekty czasem życia, jednak usunięcie obiektu nadrzędnego nie musi
oznaczać usuwania obiektów podrzędnych, gdyż mogą one uczestniczyć w
relacjach asocjacyjnych z innymi obiektami. O tym czy można usunąć
obiekty podrzędne decyduje programista/kod źródłowy. Relacja ta nie ma
bezpośredniego wsparcia w językach programowania.
Występuje często we wzorcach projektowych.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Model UML a Java
class B4 {}
class A4 {
B4 b4;
}
Najsłabsza z relacji asocjacyjnych. Wiąże obiekty czasem życia bardzo
słabo. Reprezentuje sytuację, w której są one dynamicznie podpinane
wzajemnie do siebie lub odpinane od siebie. Usunięcie jednego obiektu nie
implikuje usunięcia drugiego obiektu. Kod źródłowy w Java dla tej relacji
jest identyczny jak dla relacji agregacji. Jedyna różnica polega w sposobie
zarządzania czasem życia obiektów.
Często spotykana we wzorcach projektowych.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Model UML a Java
class B5 {}
class A5 {
void method(B5 b5) {}
}
Relacja zależności jest relacją najsłabiej wiążącą ze sobą klasy. Oznacza
ona, że jeśli wprowadzono zmianę do klasy B5, to zmiana ta może, ale nie
musi wpłynąć na kod źródłowy klasy A5.
Należy dążyć do maksymalnego wykorzystywania tej relacji. Odgrywa
ona ważną rolę w dekompozycji funkcjonalnej systemów oprogramowania.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Model UML a Java
Typowy dla wielu wzorców schemat dekompozycji odpowiedzialności
można zilustrować dekompozycją hierarchii dziedziczenia łączącej w
sobie zbyt wiele odpowiedzialności na hierarchie dziedziczenia połączone
słabą relacją asocjacyjną, zwykle relacją asocjacji.
Schemat ten został zilustrowany na kolejnym slajdzie.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Model UML a Java
•
•
Omówienie kwestii osłabiania relacji otwiera drogę do omówienia:
Wzorców projektowych
Wstrzykiwania zależności w Spring
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Obiektowość w Java
Zostaną przedstawione podstawowe konstrukcje językowe wspierające
4 wyróżniki obiektowości:
• Abstrakcja
• Enkapsulacja
• Dziedziczenie
• Polimorfizm
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Obiektowość w Java - abstrakcja
Mechanizm służący ukrywaniu implementacji przed jej
użytkownikiem. W podejściu obiektowym wspierany jest przez pojęcia:
• Interfejsu (obiekt jako instancja klasy lub jako komponent)
• Klasy abstrakcyjnej
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Obiektowość w Java - abstrakcja
Interfejs
W Java wykorzystuje się słowa kluczowe:
interface
implements
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Obiektowość w Java - abstrakcja
Klasa abstrakcyjna
W Java wykorzystuje się słowo kluczowe:
abstract
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Obiektowość w Java - enkapsulacja
Ochrona dostępu do metod lub danych.
W Java wykorzystuje się słowa kluczowe:
private
protected
public
package
Domyślny jest package. Jest on związany z koncepcją podziału
elementów kodu źródłowego na pakiety – pojęcie z UML. Pełnią one w
Java rolę przestrzeni nazw reprezentowanej w C++ przez namespace.
Nawiązać do pakietu i podsystemu w UML. Podkreślić znaczenie.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Obiektowość w Java - dziedziczenie
Dziedziczenie oznacza, że jedna klasa jest uogólnieniem drugiej. Klasa
będąca jej uszczegółowieniem przejmuje cechy swojej nadklasy –
atrybuty i/lub zachowania.
W Java wykorzystuje się słowo kluczowe:
extends
W Java dziedziczenie pomiędzy klasami jest zawsze jednokrotne –
nie ma wielodziedziczenia pomiędzy klasami. Jednocześnie Java
umożliwia stosowanie wielodziedziczenia pomiędzy interfejsami.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Obiektowość w Java - polimorfizm
Zachowywanie się jednych obiektów jakby były szczególnymi
rodzajami obiektów innych klas. Zachowania zawsze dotyczą obiektów, a
rodzaje – klas, ponieważ klasy te mogą być abstrakcyjne, a więc mogą nie
mieć swoich instancji. Polimorfizm dotyczy operacji a nie danych.
Do realizacji polimorfizmu wykorzystuje się dziedziczenie i
rzutowanie w górę.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Obiektowość w Java - przykład
Wydawanie odgłosów przez zwierzęta.
Klasa abstrakcyjna Animal – w rzeczywistym świecie nie ma instancji.
[wszystkie klasy w jednym pakiecie]
[nie korzystamy z interfejsów]
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Animal.java
package pl.edu.pk.javaprogramming.animals;
public abstract class Animal {
abstract public String say();
}
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Obiektowość w Java - przykład
Klasy zwierząt konkretnych – podklasy klasy abstrakcyjnej Animal.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Dog.java, Cat.java
package pl.edu.pk.javaprogramming.animals;
public class Dog extends Animal {
public String say() {
return "Hau";
}
}
package pl.edu.pk.javaprogramming.animals;
public class Cat extends Animal{
public String say() {
return "Miau";
}
}
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Obiektowość w Java - przykład
Klasa główna z metodą główną.
[biblioteka kontenerów ale bez iteratora]
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
AskAnimals.java
package pl.edu.pk.javaprogramming.animals;
import java.util.ArrayList;
import java.util.List;
public class AskAnimals {
private static List<Animal> listOfAnimals = new
ArrayList<Animal>();
public static void main(String[] args) {
listOfAnimals.add(new Dog());
listOfAnimals.add(new Cat());
listOfAnimals.add(new Dog());
for(int i=0; i<3; i++)
System.out.println(listOfAnimals.get(i).say());
}
}
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Klasyfikacja wzorców projektowych
•
•
•
Wg rodzaju:
Kreacyjne
Strukturalne
Czynnościowe
•
•
Wg zakresu
Obiektowe
Klasowe
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Klasyfikacja wzorców projektowych
Rodzaj
Kreacyjne
Zakres Klasy
Obiekty
dr inż..Piotr Zabawa
Strukturalne
Czynnościowe
Factory Method
Adaptor (klasy) Interpreter
Template Method
Builder
Abstract Factory
Prototype
Singleton
Adaptor
(obiekty)
Decorator
Facade
Composite
Bridge
Proxy
Flyweight
Instytut Informatyki
Iterator
Chain of Responsibility
Mediator
Observer
Visitor
Memento
Command
State
Strategy
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Sposób specyfikowania wzorców
• nazwa wzorca i jego kategoria
• przeznaczenie
• inne nazwy
• uzasadnienie stosowania
• stosowalność
• struktura
• uczestnicy
• współpraca
• konsekwencje
• implementacja
• przykłady
• znane zastosowania
• pokrewne wzorce
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Przykłady wzorców projektowych
Przykłady wszystkich wzorców GoF zaimplementowane w Java:
http://www.fluffycat.com/Java-Design-Patterns/
Znajdują się tam jedynie fragmenty kodów źródłowych. Cały projekt
pod Eclipse jest dostępny do pobrania z:
http://riad.usk.pk.edu.pl/~pzabawa/StaticXHTML/files/samples/PKDP_samples.zip
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorce projektowe
•
•
•
•
Wprowadzenie wzorców projektowych otwiera drogę do omówienia:
Typów prostych i ich opakowań
Definicji interfejsów i klas
Klas wewnętrznych
Programowania aspektowego
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec strukturalny
Dalej zostanie omówiony strukturalny wzorzec projektowy Dekorator.
Na wykładzie przedstawiony zostanie w ujęciu GOF w sposób ogólny, a
na laboratorium w postaci implementacji Java w ujęciu Fluffycat.
Powodem omawiania tego wzorca jest intensywne wykorzystywanie
go przez programistów Java SE w bibliotekach działających na
strumieniach, czyli:
•
•
•
java.io
java.nio
java.util.zip
Przykład wywołania:
DataOutputStream os = new DataOutputStream(
new BufferedOutputStream (
new FileOutputStream (fileName)));
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec strukturalny
Wprowadzenie tego wzorca otwiera drogę do omówienia biblioteki
wejścia/wyjścia i strumieni w Java.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Dynamicznie dołącza do obiektów dodatkowe zobowiązania.
Zapewnia elastyczną alternatywę dla tworzenia podklas w celu
rozszerzania funkcjonalności.
Inne nazwy:
Opakowanie (Wrapper)
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Uzasadnienie stosowania:
Czasami chcemy dołączyć pewne zobowiązania do niektórych
obiektów a nie całych klas. Np. dodanie ramek i pasków przewijania do
składników GUI.
Dziedziczenie jest kłopotliwe – statyczny wybór ramki, na dodatek dla
każdego elementu.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Lepszym rozwiązaniem jest umieszczenie obiektu dekorowanego
(element GUI) wewnątrz obiektu dekorujacego (ramka, scrollbars).
Dekorator dostosowuje się do interfejsu dekorowanego obiektu stając
się przeźroczystym dla klienta obiektu dekorowanego.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Dekorator przekazuje żądania do obiektu dekorowanego i może
wykonywać dodatkowe operacje przed lub po otrzymaniu żądania.
Przeźroczystość ta umożliwia rekurencyjne zagnieżdżanie dekoratorów.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Mamy obiekt klasy WidokTekstowy wyświetlający tekst w okienku.
Standardowo nie ma on suwaków. Możemy je dodać za pomocą
DekoratorZSuwakami. Ramkę możemy dodać za pomocą
DekoratoraZRamkami. Klasy DekoratorZSuwakami i
DekoratoraZRamkami są podklasami abstrakcyjnej klasy Dekorator
reprezentującej komponenty wizulane, które ozdabiają inne komponenty
wizualne.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Klasa Dekorator przesyła żądania do swojego komponentu a podklasy
mogą rozszerzać to działanie. Jeśli klient wie jaki dekorator został
wykorzystany, to może skorzystać z tych rozszerzeń.
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Stosowalność:
• dynamiczne i przeźroczyste dodawanie zobowiązania do pojedynczych
obiektów
• dodanie zobowiązań, które mogą zostać cofnięte
• niepraktyczne rozszerzanie przez podklasy – mnóstwo niezależnych
rozszerzeń może spowodować eksplozję hierarchii.
Struktura:
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Uczestnicy:
• Komponent (KomponentWizualny)
– definiuje interfejs obiektów, do których można dynamicznie
dołączać zobowiązania
• KomponentKonkretny (WidokTekstowy)
– definiuje obiekt, do którego można dołączać dodatkowe
zobowiązania
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
•
Dekorator
– zarządza odwołaniem do obiektu Komponent i definiuje interfejs
dopasowany do interfejsu Komponentu
• DekoratorKonkretny (.,.)
– dodaje zobowiązania do Komponentu
Współpraca:
• Dekorator przesyła żądania do swojego obiektu Komponent. Może
opcjonalnie wykonywać inne operacje przed lub po przesłaniu żądania
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Konsekwencje:
• większa elastyczność niż przy stosowaniu statycznego dziedziczenia –
runtime, mieszanie zobowiązań, wielokrotne dołączanie właściwości
(podwójna ramka)
• unikanie przeładowanych właściwościami klas na szczycie hierarchii –
koncepcja prostej klasy na szczycie wzbogacanej w miarę potrzeb
przez dekoratory
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
•
•
Dekorator i jego komponent nie są identyczne
wiele małych obiektów – takie systemy składają się z wielu małych
połączonych ze sobą w skomplikowany sposób obiektów – ich autorzy
mogą je bardzo łatwo zmieniać, ale trudno je zrozumieć i trudno
usuwać z nich błędy
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Implementacja:
• zgodność interfejsów obiektu dekorujacego i dekorowanego
• pomijanie klasy abstrakcyjnej Dekorator – gdy dodajemy tylko jedno
zobowiązanie (po co ujednolicać interfejsy)
• utrzymanie lekkości klasy Komponent – nie powinna definiować
danych
• zmiana skóry obiektu (Decorator) a zmiana wnętrza obiektu (Strategy)
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Przykłady:
Znane zastosowania:
• GUI
• strumienie IO [rys.]
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Wzorzec Strukturalny: Dekorator
Pokrewne wzorce:
• Adapter – zmienia interfejs a nie tylko zobowiązania.
• Kompozyt. Decorator to zdegenerowany Kompozyt z jednym
komponentem.
• Strategia – zmienia wnętrze obiektu, a Dekorator zewnętrze –
konkurencyjny sposób zmieniania obiektu (Strategia - gdy klasa
Komponent jest ciężka)
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki
Zakład Inżynierii Oprogramowania
Koniec
dr inż..Piotr Zabawa
Instytut Informatyki
Wydział Fizyki, Matematyki i Informatyki

Podobne dokumenty