Polimorfizm klasy abstrakcyjnej figur geometrycznych zadanie

0

Witam! Znajomy dostał zadanie na studia o takiej treści i w sumie ta część poszła gładko:

Tutaj rozszerzenie wcześniejszego polecenia gdzie trzeba zmienić kilka rzeczy by korzystało z polimorfizmu #

I nie do końca jesteśmy pewni czy jest dobrze zrobione że Figure to klasa abstrakcyjna a nie interfejs?
Dwa kod wydaje się "brudny" i nie bardzo wiem jakby go uporządkować.
Metoda move() w klasie Figure jest pusta bo gdy jej tam nie było sypało błędami, a to tak chyba nie za ładnie mieć pustą metodę?

Czekam na konstruktywną krytykę oraz propozycje jak ulepszyć kod.

Tutaj link to gitHub: https://github.com/s0bieskii/FiguresExercise

5

Spojrzałem w kod i mam kilka uwag:
Klasa Figure:

  • po co pole area? Nie wystarczy metoda abstrakcyjna getArea(), wyprowadzone klasy niech ją implementują i obliczają, ale wyników obliczeń nie ma sensu przechowywać w polu klasy.
  • metoda move() powinna być abstrakcyjna, podobnie jak getArea().
public abstract void move(double dx, double dy);

Klasa Rectangle:

  • setery setP1 i setP2 powinny aktualizować także pola p12 i p21, czyli współrzędne pozostałych rogów. Te pola są zbędne i komplikują kod, nie lepiej liczyć współrzędne tych rogów tylko w metodzie getArea().

Klasa StandarizedPicture:

public boolean checkLabel(Figure fig){
        Pattern rex=Pattern.compile("^[A-Z]{1}[A-Z0-9]*$");
        Matcher matcher=rex.matcher(fig.getLabel());
        if(matcher.matches()){
            return true;
        }
        return false;
    }

Zmienna lokalna rex powinna być składową klasy, najlepiej final static, wystarczy raz skompilować i korzystać, a tutaj każde wywołanie metody to tworzenie i kompilowanie od nowa.
Wartość zwracana to po prostu return matcher.matches().

No i najważniejsze: klasa Picture powinna dziedziczyć po Figure, aby musiały zaimplementować metodę getArea() i move() zamiast metody sum, która za dużo nie mówi co robi. W ten sposób możesz składać obrazki z innych obrazków i dostajesz wzorzec kompozytu. Zresztą to jest zapisane w wymaganiach zadania 4 w trzecim punkcie.

2

@s0bieskii:
Spróbuj tak. Wtedy kod o wiele prostszy i jak wprowadzisz następną figurę dziedziczącą z Figury to dalej będzie działać bez przerabiania ;-)

private static void move(Picture picture, int i) {
            Figure f = picture.getFigure(i-1);
            if (f == null) {
                System.out.println("Brak elementu w kolekcji");
            } else {
                f.move(v.getDx(), v.getDy());
            }
}

żebyś tylko mógł się odwoływać w ten sposób do metody f.move(int dx, int dy) a Twój program "wiedział" jakiej klasy obiekt chcesz przesunąć to musisz albo:
a) stworzyć interface np.

interface IFigury{
    void move(int dx, int dy);
}

a twoje klasy (konkretne figury i obraz) muszą go zaimplementować, czyli np tak:

class Linia implements IFigury {
    protected Punkt P1, P2;
    @Override
    public void move(int dx, int dy) {
        P1.move(dx, dy);
        P2.move(dx, dy);
    }
}

adnotacja @Override której widziałem, że używasz "podpowiada kompilatorowi", że nadpisujesz metodę, która jest wirtualna (!), czyli zdefiniowana wcześniej w interface lub w klasie bazowej abstrakcyjnej (lub nie) z której dziedziczysz. Bez adnotacji też działa tak samo, ale gdy zrobisz np literówkę, to zamiast nadpisać wirtualną metodę z klasy bazowej wprowadzisz niechcący nową metodę.
(!) W Javie wszystkie metody niestatyczne są wirtualne.
Spójrz teraz na rozwiązanie b. Teraz będzie bez interfejsów.
b)

public abstract class Figure {
    public abstract void move(int dx, int dy);

class Linia extends Figure {
    protected Punkt P1, P2;
    @Override
    public void move(int dx, int dy) {
        P1.move(dx, dy);
        P2.move(dx, dy);
    }
}

Zrobienie metody abstract (która zauważ nie ma implementacji), wymusza na Tobie nadpisanie jej w klasach dziedziczących z klasy abstrakcyjnej.

2

@s0bieskii: Druga uwaga, która mi się nasunęła.
Narobiłeś sobie plików (no, chyba, że tak lubisz ;-) ), bo Java się drze, że klasa public musi być zapisana w pliku o nazwie zgodnym z nazwą klasy. No i ma rację. Ale czy wszystkie Twoje klasy muszą być publiczne? Możesz śmiało swoje figury pozbawić atrybutu "public", wrzucić do jednego pliku, np. figury.java i tylko ładnie zapakować. np.:

package pl.sobieski.z3;

Twój główny program, main.java oczywiście też musi korzystać z tego samego package. A w trzecim pliku pozbieraj sobie tools'y. Jak nazbierasz kilka swoich klas i metod, które uznasz że są dobre i uniwersalne to zrobisz sobie z tego kiedyś swoją własną library.

No i aż sie prosi by w main'ie używać jakiejś static metody do wczytywania double'i zamiast parokrotnie sie kopać z zamienianiem przecinków na kropki.
private static double podajWartosc(String komunikat)

2

To jest programowanie zorientowane objektowo.
Obiektowe bo są klasy które reprezentują obiekty.
Zorientowane objektowo - tutaj chodzi właśnie o polimorfizm. Dzięki polimorfizmowi program potrafi w inteligentny sposób wywoływać funkcje wirtualne w zależności od tego jaki obiekt potomny otrzyma - inteligentna orientacja odbywa się na podstawie referencji (wskaźnika) do klasy(interfejsu) bazowej.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.