• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Wywołanie metody o odpowiednim typie argumentu.

Object Storage Arubacloud
0 głosów
290 wizyt
pytanie zadane 19 stycznia 2017 w Java przez zperkowski Stary wyjadacz (11,150 p.)

Witam! Szukam sposobu na to by w Javie udało się wywołac jedną z kilku metod o takiej samej nazwie, ale o różnych typach argumentów, zależnie od przekazywanego argumentu. Chciałbym znaleźć sposób na to by Java w jakiś sposób się zorientowała jakiej z jakiej klasy pochodzi dany objekt przekazany jako argument przy wywoływaniu metody.

W tym momencie sprawdzam jakiego typu jest klasa poprzez objekt.getClass().getName(), a następnie castuje do odpowiedniego typu, co nie do pozwala na dużą elastyczność kodu. Chciałbym pozbyć się sztywnego sprawdzania String'a w switchu. U mnie klasa Product jest klasą główną, a Instrument dziedziczy z Product. Jest jeszcze kilka innych klas pochodnych, ale zostały pominięte dla uproszczenia kodu. Objekt treeProducts to objekt TreeView (zawierający objekty TreeItem<Product>) z JavyFX. Listener wywołuje metodę wypełniającą informacje o zaznaczonym produkcie. Tak wygląda wspomniany sposób:

treeProducts.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TreeItem<Product>>() {
                @Override
                public void changed(ObservableValue<? extends TreeItem<Product>> observable, TreeItem<Product> oldValue, TreeItem<Product> newValue) {
                    switch (newValue.getValue().getClass().getName()) {
                        case "com.dupa.Product":
                            fillDetailOfProduct(newValue.getValue());
                            break;
                        case "com.dupa.Instrument":
                            fillDetailOfProduct((Instrument) newValue.getValue());
                            break;
                    }
                }
            }
        );

 

private void fillDetailOfProduct(Product product) {
// ...
}

private void fillDetailOfProduct(Instrument product) {
fillDetailOfProduct( (Product) product);
// ...
}

Próbówałem użyć wildcars stosując w Listenerze `<? extends Product>` zamiast `<Product>` i usunąć ww. switcha, ale po użyciu tego sposobu wykonuje się wyłącznie fillDetailOfProduct(Product product) niezależnie od klasy przekazanego objektu.

Ma ktoś z Was jakieś sugestie co mógłbym zrobić by mój pomysł zadziałał? A jeżeli czegoś takiego nie da się wykonać, to czy istnieje jakaś alternatywa na moje sprawdzanie nazwy klasy?

2 odpowiedzi

+1 głos
odpowiedź 19 stycznia 2017 przez K0XM4N Gaduła (3,640 p.)

Z tego co zrozumiałem czytając Twój post, chcesz osiągnąć pewną funkcjonalność dla danego typu obiektu bez sprawdzania z jakiej klasy pochodzi. Możesz pozbyć się tego problemu stosując Strategie, czyli wzorzec projektowy.

Tak w skrócie, polega to na tym, że będziesz mógł przekazać obiekty "dowolnego typu" do metody. Metoda nie będzie zwracała na to uwagi jakiego typu jest obiekt, a wykona odpowiednie operacje. Zapewnia to dużą elastyczność, bo w momencie gdy zdecydujesz się dodać nową klasę i rozszerzyć ją o superclassę "Product" (tą bazową), nie będziesz musiał dodawać jakiś switchy czy ifów decydujących o funkcjonalności. Nie mieszasz w kodzie, a zyskujesz nową funkcjonalność :)

Jak to działa?

1. Najpierw tworzysz interfejs dla charakterystycznej operacji. Deklarujesz metodę.
2. Klasa główna implementuje powyższy interfejs i implementuje metodę z interfejsu.
3. Klasy pochodne przesłaniają ową metodę i nadajesz im odpowiednią funkcjonalność.
4. W klasie gdzie chcesz dodawać "Produkty" do TreeView, deklarujesz metodę, którą będzie to robić. Ale podajesz typ argumentu jako ten interfejs, który na początku stworzyłeś.
5. Wygląda to np. tak:

public class AddToTreeView(){

        public void addProductToTreeView(InterfaceType interfaceArg){
                    interaceArg.add();
         }


}

Dorzucam jeszcze mały tutorial:
https://www.youtube.com/watch?v=-NCgRD9-C6o

W razie wątpliwości pisz :D
 

 

komentarz 19 stycznia 2017 przez zperkowski Stary wyjadacz (11,150 p.)

Tak w skrócie, polega to na tym, że będziesz mógł przekazać obiekty "dowolnego typu" do metody. Metoda nie będzie zwracała na to uwagi jakiego typu jest obiekt, a wykona odpowiednie operacje. Zapewnia to dużą elastyczność, bo w momencie gdy zdecydujesz się dodać nową klasę i rozszerzyć ją o superclassę "Product" (tą bazową), nie będziesz musiał dodawać jakiś switchy czy ifów decydujących o funkcjonalności. Nie mieszasz w kodzie, a zyskujesz nową funkcjonalność :)

To jest dokładnie to czego potrzebuje! Dziękuję bardzo! Na pewno spróbuje użyć tego wzorca w przeciągu kilku dni. Napiszę jak będzie lub nie będzie działać. Wygląda zachęcająco. ;)

komentarz 19 stycznia 2017 przez K0XM4N Gaduła (3,640 p.)
Przetestuj sobie ten wzorzec na jakimś prostym przykładzie, a potem zaimplementuj to sobie do projektu ;). Oczywiście każde rozwiązanie ma plusy i minusy. Tutaj plusem jest elastyczność i możliwość rozszerzania programu o dodatkowe fukcje, ale wady też ma. Więcej kodu i klas odpowiedzialnych za pewną logikę biznesową. Mimo wszystko jest to jeden z wzorców MUST KNOW ;)
–1 głos
odpowiedź 19 stycznia 2017 przez KubenQPL Maniak (62,820 p.)
W Javie jest coś takie jak polimorfia więc wystarczy że jako argument dasz Product i potem spokojnie możesz jako parametr dawać klasę dziedziczącą fillDetailOfProduct(instrument);
komentarz 19 stycznia 2017 przez zperkowski Stary wyjadacz (11,150 p.)
O istnieniu polimorfii oczywiście wiem, ale nie rozumiem Twojej odpowiedzi. Jakoś jedno zdanie nie jest dla mnie specjalnie pomocne. Mógłbyś użyć jakiegoś jakiegoś przykładu, który rozwiązuje mój problem?
komentarz 19 stycznia 2017 przez KubenQPL Maniak (62,820 p.)

Odpowiem po kolei na twoje pytanie. 

Witam! Szukam sposobu na to by w Javie udało się wywołac jedną z kilku metod o takiej samej nazwie, ale o różnych typach argumentów, zależnie od przekazywanego argumentu. Chciałbym znaleźć sposób na to by Java w jakiś sposób się zorientowała jakiej z jakiej klasy pochodzi dany objekt przekazany jako argument przy wywoływaniu metody.

Jeśli chodzi o to, to wystarczy zrobić kilka metod tak samo nazwanych tylko przyjmujących różne argumenty, potem to już automatycznie użyje odpowiedniej metody poznając po parametrze, tak jak to zrobiłeś.

public void fillDetailOfProduct(Product p){}
public void fillDetailOfProduct(Instrument p){}

Jeśli zaś chodzi o to sprawdzanie po nazwie to nie ma po co tego robić, klasy dziedziczącej możesz używać tak samo jak klasy rodzica czyli wszędzie gdzie jako argument podajesz Product możesz bez castowania podawać Instrument jeśli dziedziczy po Product.

Jeśli dalej to nie to o co ci chodziło to zparafrazuj pytanie.

komentarz 19 stycznia 2017 przez zperkowski Stary wyjadacz (11,150 p.)

Jeśli chodzi o to, to wystarczy zrobić kilka metod tak samo nazwanych tylko przyjmujących różne argumenty...

A co ja wyżej zrobiłem? Dwie metody, które nazywają się tak samo (fillDetailOfProduct) i przyjmują różne argumenty (typu Product i Instrument).

Wydaje mi się, że dochodzisz to takich samych wniosków co ja, czyli uważasz, że to co napisałeś powinno działać. Zadałem te pytanie, ponieważ nie dzieje się tak.

newValue w tym przykładzie można potraktować jako jakąś listę List<Product>, gdzie dodane są dwa elementy. Pierwszy o typie Product, a drugi o typie Instrument. Po wywołaniu ww. metod okaże się, że dla obydwóch wywłołała się metoda fillDetailOfProduct(Product p), a nie fillDetailOfProduct(Instrument p).

 

package com.company;

public class Product {
    private String name;

    public Product(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.company;

public class Instrument extends Product {
    private int price;

    public Instrument(String name, int price) {
        super(name);
        this.price = price;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }
}
package com.company;

import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {
        ArrayList<Product> productArrayList = new ArrayList<>();

        productArrayList.add(new Product("Pierwszy"));
        productArrayList.add(new Instrument("Drugi", 15));

        showDetails(productArrayList.get(0));
        showDetails(productArrayList.get(1));
    }

    static private void showDetails(Product product) {
        System.out.println(product.getName());
    }

    static private void showDetails(Instrument instrument) {
        System.out.println(instrument.getPrice());
    }

}

To jest wynik programu:

Pierwszy
Drugi

A oczekuje, że się wykona:

Pierwszy
15

 

Podobne pytania

+1 głos
1 odpowiedź 177 wizyt
pytanie zadane 23 maja 2015 w Rozwój zawodowy, nauka, praca przez Pan Kulomb Pasjonat (18,630 p.)
0 głosów
2 odpowiedzi 531 wizyt
pytanie zadane 5 maja 2019 w Java przez poldeeek Mądrala (5,980 p.)
0 głosów
1 odpowiedź 334 wizyt
pytanie zadane 31 października 2017 w Java przez wojtek2002 Nowicjusz (140 p.)

92,537 zapytań

141,377 odpowiedzi

319,456 komentarzy

61,922 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...