Cel: Refaktoryzacja, Abstrakcyjna Klasa Bazowa, Polimorfizm, Dziedziczenie. Anna zauważyła poważny błąd w założeniach symulatora. Obecny model traktuje wszystko jak "Akcję" (Stock), co jest finansową bzdurą.
W rzeczywistości inwestowanie w ropę naftową działa inaczej niż kupno akcji Apple, a handel walutami obarczony jest zupełnie innymi kosztami niż handel papierami wartościowymi.
Uczestnicy warsztatów zaczęli narzekać, że symulator przekłamuje wyniki, bo nie uwzględnia specyfiki różnych rynków. Twoim zadaniem jest całkowita przebudowa warstwy danych (tzw. Domain Model), aby system obsługiwał różne typy instrumentów finansowych w sposób polimorficzny.
Twoim zadaniem nie jest dopisanie kodu, ale jego generalizacja. Klasa Portfolio nie może już zależeć od klasy Stock. Musi operować na ogólnym pojęciu "Aktywa".
Struktura pakietów:
src/main/java/com/stockmarket/
├── domain/ <-- Tu ma trafić cała hierarchia aktywów
├── logic/ <-- Tu ma trafić logika portfela (Portfolio)
└── Simulation.java <-- Klasa startowa (opcjonalnie)
Musisz zaprojektować hierarchię klas, która zastąpi obecną klasę Stock.
Stwórz abstrakcyjny byt reprezentujący dowolny walor, który posiada unikalny identyfikator, nazwę oraz bieżącą wycenę rynkową.
Wymaganie: Klasa ta musi wymuszać na swoich "dzieciach" zaimplementowanie logiki wyliczania Wartości Rzeczywistej. Wartość rzeczywista to nie to samo co "cena * ilość". Każdy rynek pomniejsza wartość o inne ukryte koszty (szczegóły poniżej).
Zastąp dawną klasę Stock nową klasą Share. To najprostszy instrument. Jego wartość to czysta wycena rynkowa. Jednakże, każda transakcja akcjami obciążona jest stałą "Opłatą Manipulacyjną" (np. 5 zł), która jest kosztowniejsza przy małych kwotach, a pomijalna przy dużych.
Surowce (np. złoto, ropa) fizycznie istnieją, więc ich posiadanie kosztuje (magazynowanie, ubezpieczenie).
Zaprojektuj klasę tak, aby uwzględniała "Koszt Przechowywania" (Storage Cost).
Algorytm wyceny musi symulować utratę wartości w czasie. Przy każdej wycenie wartości portfela, wartość surowca musi być pomniejszona o procentowy koszt magazynowania zależny od wolumenu (im więcej posiadasz, tym droższe jest składowanie).
Waluty kupuje się po innej cenie, a sprzedaje po innej (Spread). Klasa ta musi przechowywać informację o "Spreadzie" (różnicy kursowej). Wyceniając waluty w portfelu, system musi zawsze podawać kwotę, którą inwestor realnie by dostał ("Bid Price"), czyli cenę rynkową pomniejszoną o spread, a nie "czystą" cenę rynkową.
Klasa Portfolio wymaga gruntownego przepisania. Nie może ona zawierać żadnych instrukcji if sprawdzających typ obiektu (np. zakaz używania instanceof czy getClass() == ...).
Cała logika musi opierać się na metodach nadpisanych w klasach opisanych w Zadaniu 1.
Metoda dodająca aktywo do portfela musi być uniwersalna. Musi przyjmować dowolny typ aktywa. Musi weryfikować, czy inwestora stać na zakup, uwzględniając specyficzne dla danego rynku opłaty początkowe (które musisz zdefiniować w klasach aktywów).
Stwórz metodę raportującą stan majątku. Metoda ta ma iterować po zawartości portfela i sumować wartość wszystkich aktywów.
Kluczowe wyzwanie: Metoda ta ma wywołać tę samą metodę na każdym obiekcie z listy, ale wynik ma być inny dla Akcji (cena rynkowa), inny dla Surowca (cena pomniejszona o magazynowanie) i inny dla Waluty (cena pomniejszona o spread). To jest test na poprawne użycie polimorfizmu.
To najważniejsza część zadania. Anna nie zaakceptuje kodu, który "działa na oko".
Stwórz test, w którym do jednej tablicy/listy wrzucisz Akcję, Surowiec i Walutę o tej samej cenie bazowej (np. 100.0) i tej samej ilości. Następnie wywołaj na nich metodę wyliczającą wartość.
Asercja musi potwierdzić, że każdy z tych obiektów zwrócił INNĄ wartość końcową, mimo tej samej ceny wejściowej.
Sprawdź, czy Surowiec traci na wartości przy dużej ilości (wysoki koszt magazynowania).
Sprawdź, czy Waluta zawsze jest warta mniej niż cena rynkowa (ze względu na spread).
Zabezpiecz portfel. Próba zakupu aktywa, na które nas nie stać (uwzględniając ukryte koszty danej klasy!), musi kończyć się błędem, a nie ujemnym stanem konta.
Wskazówka:
Jeśli w klasie Portfolio napiszesz kod w stylu: if (asset.type == "Stock") { ... } lub if (asset instanceof Currency) { ... } ...to zadanie zostanie zaliczone na 0 punktów. Portfolio ma "nie wiedzieć", co posiada – ma ufać, że obiekt sam wie, jak policzyć swoją wartość.
| Kryterium | Punkty | Opis |
|---|---|---|
| Zadanie 1 | 4 | |
| Klasa abstrakcyjna | 1 | uwzględnienie wskazanych pól oraz logiki Wartości Rzeczywistej |
| Rynek akkcji | 1 | metody obsługujące akcje akcje z uwzględnieniem Opłaty Manipulacyjnej |
| Rynek surowcowy | 1 | metody obsługujące surowce z uwzględnieniem Kosztu przechowywania |
| Rynek walutowy | 1 | metody obsługujące waluty z uwzględnieniem "spreadu" |
| Zadanie 2 | 2 | |
| Mechanizm zakupu | 1 | uniwersalność metod w uwzględnieniem błędów |
| Audyt portfela | 1 | poprawne zastosowanie polimorfizmu |
| Wymagania testowe | 4 | |
| Test polimorfizmu | 1 | Sprawdzenie czy metody portfela wywołują właściwe implementacje metod z klasy bazowej |
| Test logiki biznesowej | 1 | sprawdzenie czy metody poprawnie realizują założenia zadań |
| Test wyjątków | 1 | weryfikacja czy błędy przewidziane w implementacji są rzeczywiście zgłaszane |
| Pozostałe testy | 1 | testy powinny w pełni pokryć kod, jeśli kod przewiduje wiele sytuacji to każda powinna posiadać osobny test |