Programowanie obiektowe Laboratorium z przedmiotu Programowanie obiektowe - zestaw 02 Cel zajęć. Celem zajęć jest zapoznanie z praktycznymi aspektami projektowania oraz implementacji klas i obiektów z wykorzystaniem dziedziczenia. Wprowadzenie teoretyczne. Rozważana w ramach niniejszych zajęć tematyka jest ważna, gdyż dziedziczenie i polimorfizm są mechanizmami wykorzystywanymi powszechnie w programowaniu obiektowym. Aby ze zrozumieniem zrealizować zadania, przewidziane do wykonania w ramach zajęć laboratoryjnych, należy znać znaczenie pojęć takich jak: dziedziczenie, klasa bazowa, klasa potomna, polimorfizm, metoda wirtualna, kolekcja List<T> i jej podstawowa funkcjonalność. Należy również znać podstawy języka modelowania systemów informatycznych UML. 1. Dziedziczenie Dziedziczenie polega na tworzenie nowej klasy na podstawie klasy już istniejącej. W języku C# dziedziczeniu podlegają: pola klasy, właściwości oraz metody. Podobnie jak w C++ elementy klasy, które w klasie bazowej zostały oznaczone jako „public” lub „protected”, w klasie potomnej również będą miały ten sam zakres widoczności, natomiast elementy oznaczone jako „private” lub „internal” nie podlegają dziedziczeniu. Mechanizm dziedziczenia przedstawia poniższy przykład: Przykład 1 – Dziedziczenie 1 Programowanie obiektowe Proszę zwrócić szczególną uwagę na linię kodu numer 32, w której wywoływany jest konstruktor klasy bazowej. W języku C# do wywołania konstruktora klasy bazowej wykorzystywane jest słowo kluczowe „base”. Klasa bazowa (na przykładzie 1 - „Budynek”) to klasa, po której dziedziczy inna klasa nazywana klasą potomną (na przykładzie 1 - „BudynekMieszkalny”). 2. Polimorfizm Pojęcie polimorfizmu odnosi się do klas, które współdzielą te same metody, ale implementują je w różny sposób. W praktyce oznacza to, że klasa potomna dziedzicząca daną metodę z klasy bazowej, może przypisać jej zupełnie inną funkcjonalność. Mechanizm polimorfizmu przedstawia poniższy przykład: Przykład 2 – Polimorfizm 2 Programowanie obiektowe Proszę zwrócić uwagę na sposób działania metody „WypiszInfo”. W linii 60 zostaje wywołana metoda klasy bazowej, natomiast w liniach 62, 64 zostaje wywołana metoda klasy potomnej. Proszę zauważyć, że w linii 63 do zmiennej typu „Budynek” zostaje przypisany obiekt „BudynekMieszkalny”, a w linii 64 zostaje wywołana metoda „WypiszInfo” z klasy potomnej. Zadziałał tu mechanizm polimorfizmu. Metody z klasy bazowej, które mogą zostać przesłonione przez metody o tej samej nazwie z klasy potomnej, należy oznaczyć modyfikatorem „virtual” (linia 25 w przykładzie 2). Metody te są metodami wirtualnymi. Metody z klasy potomnej, które mają przesłonić metodę o tej samej z klasy bazowej, należy oznaczyć modyfikatorem „override” (linia 49 w przykładzie 2). 3. Kolekcja List<T> Kolekcje to pojęcia stosowane w odniesieniu do klas, które umożliwiają przechowywanie oraz efektywne przetwarzanie obiektów danego typu. Jedną z największych zalet kolekcji jest możliwość dynamicznej zmiany ich rozmiaru – liczba przechowywanych przez kolekcje elementów nie jest ograniczona w momencie utworzenia danej kolekcji, tak jak ma to miejsce w przypadku tablicy. Jednym z podstawowych typów kolekcji jest lista - List<T>. Proste operacje wykonywane na liście zostaną przedstawione do celów niniejszego laboratorium. Szczegółowe omówienie możliwości listy i innych kolekcji nastąpi na wykładzie. Informacje dotyczące kolekcji List<T> niezbędne do wykonania zadania laboratoryjnego: Klasa List<T> została zdefiniowana w przestrzeni nazw „System.Collections.Generic”. Litera „T” oznacza typ obiektów przechowywanych przez listę. Utworzenie obiektu listy odbywa się za pomocą konstrukcji: List<T> nazwaListy = new List<T>( ) gdzie „T” stanowi nazwę typu przechowywanego obiektu. Podstawowe metody i właściwości listy prezentuje poniższy przykład: 3 Programowanie obiektowe Przykład 3 – Metody kolekcji List<T> 4. UML – dziedziczenie na diagramie klas Dziedziczenie w języku UML oznaczane jest za pomocą strzałki z pustym grotem wskazującym na klasę bazową. Rys. 1 – Reprezentacja dziedziczenia języku UML 4 Programowanie obiektowe Zadanie 1. Proszę zrealizować aplikację obiektową, która powinna odznaczać się następującymi cechami: Aplikacja powinna zawierać klasy zaimplementowane zgodnie z zamieszczonym poniżej diagramem klas. Metody „WypiszInfo” powinny wypisywać na konsoli informacje na temat wartości wszystkich pól obiektów. Metoda „WypiszInfo” klasy „Osoba” powinna być wirtualna, metody „WypiszInfo” w klasach pochodnych („Student”, „Piłkarz”), powinny ją przesłaniać. Metoda „StrzelGola” powinna zwiększać o 1 wartość pola „liczbaGoli”. Aby zrealizować zadanie należy wykonać następujące kroki: Proszę o implementację klasy bazowej „Osoba”, jej pól i metod. Proszę pamiętać o modyfikatorze „virtual”, który powinna posiadać metoda „WypiszInfo”. Proszę o implementację klasy pochodnej „Student”, jej pól i metod. Proszę pamiętać o modyfikatorze „override”, który powinna posiadać metoda „WypiszInfo”. Proszę o implementację klasy pochodnej „Pilkarz”, jej pól i metod. Proszę pamiętać o modyfikatorze „override”, który powinna posiadać metoda „WypiszInfo”. Proszę o przetestowanie poprawności wykonania zadania za pomocą kodu testowego: 5 Programowanie obiektowe Przy ocenie zadania główny nacisk będzie kładziony na: Prawidłową implementację dziedziczenia. Prawidłowy dobór modyfikatorów dostępu. Zadanie 2. Proszę zrealizować aplikację obiektową, która powinna odznaczać się następującymi cechami: Aplikacja stanowi rozszerzenie aplikacji z zadania nr 1. Aplikacja powinna zawierać klasy zaimplementowane zgodnie z zamieszczonym poniżej diagramem klas. Obiekty klasy „Student” powinny przechowywać kolekcję obiektów klasy „Ocena” za pomocą listy. Metoda „DodajOcene” ma dodawać ocenę do listy ocen studenta. Metoda „WypiszOceny( )” ma wypisywać informacje o wszystkich ocenach studenta. Metoda „WypiszOceny(string nazwaPrzedmiotu)” z przedmiotu o podanej nazwie. Metoda „UsunOcene” ma usuwać ocenę studenta o podanych parametrach. Metoda „UsunOceny( )” ma usuwać wszystkie oceny studenta. Metoda „UsunOceny(string nazwaPrzedmiotu)” ma usuwać wszystkie oceny studenta z przedmiotu o podanej nazwie. Metoda „WypiszInfo” z klasy „Student” ma wypisywać także informacje o wszystkich ocenach studenta. 6 ma wypisywać informacje o ocenach studenta Programowanie obiektowe Aby zrealizować zadanie należy wykonać następujące kroki: Proszę o implementację klasy „Ocena”, jej pól i metod. Proszę o implementację w klasie „Student” następującego pola: Następnie proszę o dołączenie do projektu przestrzeni nazw „System.Colections.Generic”, z której pochodzi używana kolekcja typu „List<T>”, poprzez dopisanie na początku kodu instrukcji: Proszę o implementację metody „DodajOcene” w klasie „Student”. Metoda ta ma tworzyć nowy obiekt typu „Ocena” i dodawać go do listy ocen za pomocą metody „Add” obiektu typu „List<Ocena>”. Proszę o implementację metody „WypiszOceny”, która ma wypisywać na konsoli wszystkie oceny studenta. Metoda ta powinna być zaimplementowana przy użyciu pętli „foreach” lub pętli „for”. W tym celu niezbędna będzie także implementacja odpowiednich właściwości w klasie „Ocena”. Proszę o implementację metody „WypiszOceny (string nazwaPrzedmiotu)”, która ma wypisywać na konsoli wszystkie oceny studenta z przedmiotu o podanej nazwie. Metoda ta powinna być zaimplementowana przy użyciu pętli „foreach” lub pętli „for”. Proszę o implementację metody „UsunOcene”, która ma usuwać z listy ocen oceny o podanych parametrach. Do tego celu należy użyć pętli „for”: 7 Programowanie obiektowe UWAGA! W języku C# istnieje prostszy sposób realizacji usunięcia z kolekcji obiektów o podanych parametrach. Sposób ten zostanie przedstawiony na jednym z kolejnych wykładów. Proszę o implementację metody „UsunOceny”, która ma usuwać z listy ocen wszystkie oceny. Do tego celu należy użyć metody „Clear” kolekcji typu „List<Ocena>”. Proszę o implementację metody „UsunOceny (string nazwaPrzedmiotu)”, która ma usuwać z listy ocen oceny z przedmiotu o podanej nazwie. Proszę o modyfikację metody „WypiszInfo” z klasy „Student”. Ma ona wypisywać także listę wszystkich ocen studenta. Proszę o przetestowanie poprawności wykonania zadania za pomocą poniższego kodu, który ma zostać dodany do kodu testowego z poprzedniego zadania: Przy ocenie zadania główny nacisk będzie kładziony na: Poprawną implementację metod. 8 Programowanie obiektowe Prawidłowy dobór modyfikatorów dostępu. Zadanie do domu. Proszę zrealizować aplikację obiektową, która powinna odznaczać się następującymi cechami: Zadanie do domu jest rozszerzeniem zadania 1. Ilustruje je poniższy diagram klas. Proszę o utworzenie klas „PilkarzNozny” i „PilkarzReczny”, które dziedziczą po klasie „Pilkarz”. Metoda „StrzelGola” w klasie „PilkarzReczny” ma wywoływać metodę „StrzelGola” z klasy bazowej, a ponadto wypisywać na ekranie konsoli komunikat „Ręczny strzelił!”. Metoda „StrzelGola” w klasie „PilkarzNozny” ma wywoływać metodę „StrzelGola” z klasy bazowej, a ponadto wypisywać na ekranie konsoli komunikat „Nożny strzelił!”. Uwagi: Metoda „StrzelGola” w klasie „Pilkarz” powinna być wirtualna, a jej odpowiedniki w klasach potomnych powinny ją przesłaniać. Metody „StrzelGola” z klas potomnych powinny odwoływać się do swoich odpowiedników za pomocą słowa kluczowego „base” poprzez konstrukcję: „base.<nazwa metody>” 9 Programowanie obiektowe Zagadnienia, które należy uznać za przyswojone w trakcie zajęć. Po zajęciach będzie obowiązywać praktyczna znajomość: Pojęcia dziedziczenia i polimorfizmu. Tworzenie metod wirtualnych i ich przesłanianie. Wykonywanie prostych operacji na kolekcjach „List” z przestrzeni nazw „System.Collections.Generic”. Przedstawienie dziedziczenia na diagramie klas. Zagadnienia do powtórzenia na następne zajęcia. Przed kolejnymi zajęciami należy powtórzyć następujące zagadnienia: Klasy abstrakcyjne. Interfejsy. Wybrane aspekty dotyczące implementacji z wykorzystaniem języka Java. Rozważane w ramach niniejszych zajęć aspekty mogą być implementowane w różnorodnych technologiach służących do realizacji aplikacji obiektowych, m.in. języku JAVA. Zasadnicze różnice w korzystaniu z języków C# i JAVA w kontekście tematyki niniejszego laboratorium są następujące: W języku Java dziedziczenie odbywa się przy użyciu słowa kluczowego „extends”. W języku Java odpowiednikiem słowa kluczowego „base” jest słowo „super”. W języku Java wywołanie konstruktora klasy bazowej odbywa się w ciele konstruktora klasy potomnej. W języku Java nie istnieje modyfikator „virtual”, każda metoda jest domyślnie wirtualna. Z kolei analogie w korzystaniu z języka C# i JAVA w kontekście tematyki niniejszego laboratorium są następujące: W języku Java również nie istnieje wielodziedziczenie klas. Mechanizm dziedziczenia w języku Java odbywa się na takiej samej zasadzie, jak w języku C#. Uwagi szczegółowe dotyczące implementacji w języku Java są następujące: Poniższy przykład przedstawia implementację dziedziczenia w języku Java. Jest odpowiednikiem przykładu nr 1. 10 Programowanie obiektowe Przykład 4 – dziedziczenie w języku Java Poniższy przykład przedstawia mechanizm polimorfizmu w języku Java. Jest odpowiednikiem przykładu nr 2. Przykład 5 – polimorfizm w języku Java 11 Programowanie obiektowe 12