Celem laboratorium jest zapoznanie się z mechanizmem interfejsów oraz kolekcjami.
- Mechanizm interfejsów pozwala na określenie pewnego zestawu metod, które muszą być implementowane przez określony typ.
Interfejs
IWorldMapjest tego przykładem - określa on sposób interakcji mapy z zwierzętami oraz klasąMapVisualizer. - Interfejs jedynie określa, że dana klasa ma posiadać określoną metodę - dlatego w interfejsie nie ma implementacji - wszystkie metody są
z założenia abstrakcyjne (można pominąć modyfikator
abstract). - Od Javy 8 interfejsy mogą posiadać metody statyczne (takie same jak metody statyczne w klasach) oraz metody domyślne
(oznaczane modyfikatorem
default), które posiadają implementację. - W interfejsie wszystkie metody są z założenia publiczne, dlatego nie ma potrzeby dodania kwalifikatora dostępu
public. - Od Javy 9 interfejs może posiadać także metody prywatne.
- Nazwa interfejsu najczęściej zaczyna się od wielkiej litery
I. - Klasa deklaruje fakt implementacji interfejsu za pomocą słowa kluczowego
implements, np.
class RectangularMap implements IWorldMap {
}- W Javie istnieją dwie podstawowe struktury sekwencyjne (poza tablicami): LinkedList oraz ArrayList. W przeciwieństwie do tablic obie klasy pozwalają na określenie początkowego rozmiaru na 0 i dowolne rozszerzanie kolekcji.
- Obie klasy implementują interfejs
List, który definiuje podstawowe operacje na listach. - Klasy te różnią się implementację -
LinkedListoparta jest o listę dwukierunkową, przez co operacje dodawania i usuwania elementów są szybkie, ale swobodny dostęp za pomocą operatoragetjest wolniejszy.ArrayListoparta jest o tablicę, dlatego dostęp jest szybki, ale dodawanie i usuwanie elementów jest wolniejsze. - W Javie występują typy parametryzowane i typ
Listjest tego przykładem. Taki typ jest podobny do szablonów w C++. Wymaga on podania innego typu (lub typów) jako parametru (parametr musi być typem obiektowym):
List<Animal> animals = new ArrayList<>();W tym przykładzie tworzona jest lista zwierząt, a jako implementacja wybrana została klasa ArrayList. Dzięki temu
wywołania takie jak:
animals.get(1);zwracają obiekty klasy Animal, dzięki czemu mogą one być używane w "bezpieczny" sposób - tzn. kompilator może sprawdzić
czy wywoływane metody faktycznie występują w klasie Animal.
- Wykorzystaj definicje klas z poprzedniego laboratorium.
- Przyjrzyj się interfejsom
IWorldMaporazIEngine, które znajdują się w tym katalogu. - Zmodyfikuj klasę
Animalz poprzedniego ćwiczenia:- zdefiniuj konstruktor
Animal(IWorldMap map); wykorzystaj argumentmaptak, aby w metodziemovemożna było odwołać się do mapy i zweryfikować, czy zwierzę może przesunąć się na daną pozycję, - zdefiniuj konstruktor
Animal(IWorldMap map, Vector2d initialPosition), który dodatkowo określa początkowe położenie zwierzęcia na mapie, - zastanów się nad dotychczasowym konstruktorem bezparametrowym,
- zmodyfikuj metodę
toStringtak by zwracała jedynie schematyczną orientację zwierzęcia w postaci łańcucha składającego się z jednego znaku, Np. jeśli zwierzę ma orientację północną, to metodatoString()powinna zwracać łańcuch "N" albo "^". - zmodyfikuj metodę
move, tak by korzystała z wywołaniacanMoveTointerfejsuIWorldMap.
- zdefiniuj konstruktor
- Zdefiniuj klasę
RectangularMap, która:- definiuje prostokątną mapę,
- implementuje interfejs
IWorldMap - w konstruktorze akceptuje dwa parametry
widthorazheightwskazujące szerokość oraz wysokość mapy (możesz założyć że otrzymane wartości są poprawne), - umożliwia poruszanie się w obrębie zdefiniowanego prostokąta (jak w laboratorium 3),
- umożliwia występowanie więcej niż jednego zwierzęcia na mapie,
- uniemożliwia występowanie więcej niż jednego zwierzęcia na tej samej pozycji,
- posiada metodę
toStringrysującą aktualną konfigurację mapy (wykorzystaj klasęMapVisualizer, która znajduje się w tym katalogu).
- Zdefiniuj klasę
SimulationEngineimplementującą interfejsIEngine, która:- w konstruktorze akceptuje tablicę ruchów (
MoveDirection), instancję mapy (IWorldMap) oraz tablicę wektorów oznaczających początkowe pozycje zwierząt, - dodaje zwierzęta do mapy (początkowa orientacja zwierząt to
NORTH), - w metodzie
runna przemian steruje ruchem wszystkich zwierząt. Przykładowo, jeśli użytkownik wprowadzi ciąg:f b r la na mapie są dwa zwierzęta, to pierwsze zwierzę otrzyma ruchyfir, a drugiebil. Ruchy obu zwierząt mają być wykonywane na przemian, tzn. po każdym ruchu pierwszego zwierzęcia następuje ruch drugiego zwierzęcia.
- w konstruktorze akceptuje tablicę ruchów (
- Wykonaj następujący kod w metodzie
mainklasyWorld:
MoveDirection[] directions = new OptionsParser().parse(args);
IWorldMap map = new RectangularMap(10, 5);
Vector2d[] positions = { new Vector2d(2,2), new Vector2d(3,4) };
IEngine enegine = new SimulationEngine(directions, map, positions);
engine.run();Sprawdź, czy zwierzęta poruszają się poprawnie dla ciągu: f b r l f f r r f f f f f f f f.
- Dodaj testy integracyjne weryfikujące, że implementacja jest poprawna. Wykorzystaj dane z punktu 6. w celu ustalenia przebiegu testu.
- (Dla zaawansowanych) Stwórz tekstowy widget biblioteki Swing (lub innej wybranej biblioteki), który będzie wyświetlał animację poruszających się zwierzaków.
- Otaguj gotowe rozwiązanie jako lab4.