2013-07-30 16 views
14

Nie znalazłem eleganckiego sposobu rozwiązania tego problemu. Mam klasę abstrakcyjną, którą kilka innych klas dziedziczy abstrakcyjną metodą, która może zawierać od zera do 4-5 argumentów różnych typów.Metoda abstrakcyjna ze zmienną listą argumentów

public abstract class Item { 
public abstract void use(); 
} 

Na przykład, mam klasy, która dziedziczy tę książkę i nie trwa argumentów podczas używania (nadrzędne) Mam klucz klasa, która dziedziczy i ma ciąg i kolejkę jako argumenty gdy nadrzędne, etc ..

Próbowałem już używać generycznych, ale muszę wprowadzić liczbę używaną, np. Przedmiot, kiedy to faktycznie zależy od klasy.

public abstract class Item<T,U> { 
public abstract void use(T arg1, U arg2); //Number of arguments/types could be more or less 
} 

Próbowałem wysyłając zmienną listę obiektów, ale typy obiektów są zawsze zmienne i nie mam pewności co do składni, aby otrzymać w klasach dziedziczących.

public abstract class Item<T> { 
public abstract void use(T... arguments); 
} 

public class Book extends Item<?> { 
public void use(?); 
} 

public class Book extends Item<String, Queue> { //Wrong number of arguments since I can't use Item<T...> 
public void use(String str, Queue q); //fails 
} 

Po prostu robię coś złego - czy ktoś może zaoferować jakąkolwiek pomoc lub wgląd?

+0

Jeśli zrobisz "Pozycja it = new Book();", w jaki sposób proponujesz wywołanie metody 'Book.use (String, Queue);' na tym, jeśli kompilator nie może wiedzieć, jakie są poprawne typy argumentów ? A jeśli nie spodziewasz się, że kiedykolwiek będziesz miał podklasę "Przedmiotu" w zmiennej klasy nadrzędnej, dlaczego ta metoda musi być abstrakcyjna? – millimoose

Odpowiedz

12

Z tym samym pytaniem zmagałem się i nie ma idealnej odpowiedzi, ale mogę podać kilka rzeczy do rozważenia. Po pierwsze, zasadniczo próbujesz zrobić coś, co jest z natury sprzeczne z programowaniem zorientowanym na obiekt, czyli próbujesz utworzyć interfejs zmienny. Punktem interfejsu jest kod, który otrzymuje abstrakcyjną wersję obiektu (na przykład przedmiot, a nie książka), wie, jak wywołać metodę use(). Oznacza to, że muszą wiedzieć, co można przekazać do metody use(). Jeśli odpowiedź zależy od implementacji abstrakcyjnej klasy lub interfejsu, to musisz upewnić się, że kod używający go faktycznie wie jakiego rodzaju implementację (Book itp.), Której używa, w przeciwnym razie nie będzie wiedział, jak użyć wywołania() z odpowiednimi parametrami. Wygląda na to, że musisz całkowicie odmienić swój kod, szczerze mówiąc.

Istnieje jednak sposób, aby odpowiedzieć na twoje pytanie w sposób określony bez refakturowania architektury. Można utworzyć klasę, której danymi są wszystkie różne typy parametrów, które mogą zostać przekazane do metody use(), kod wywołujący ustawi pola tej klasy, a następnie przekaż ją do metody use(). Na przykład:

public class UseParameters { 
    private String string; 
    private Queue queue; 
    // Any other potential parameters to use(...) 

    public void setString(String string) { 
     this.string = string; 
    } 

    public String getString() { 
     return string; 
    } 

    // All of the other accessor methods, etc. 
} 

Następnie, można określić sposób stosowania w przypadku tak:

public abstract void use(UseParameters params); 

I każdy kod stosując produkt musiałby ustawić parametry obiektu odpowiednio miejsca:

Item item = // However you're going to get the item 
UseParameters params = new UseParameters(); 
params.setString("good string"); 
params.setQueue(new Queue()); 
item.use(params); 

Chciałbym tylko zwrócić uwagę, że jeśli powyższy kod wie, że przedmiot jest księgą (tak wie, jak ustawić ciąg i kolejkę, to dlaczego nie po prostu zdobyć książkę i pominąć potrzebującą klasę abstrakcyjną ze zmienną Metoda ble use() w ogóle? Ale dygresję. W każdym razie, książka będzie następnie wdrożyć metodę zastosowanie() tak:

@Override 
public void use(UseParameters params) { 
    if(params.getString == null || params.getQueue() == null) 
     // throw exception 

    // Do what books do with strings and queues 
} 

myślę, że robi to, co chcesz, ale należy wziąć pod uwagę refaktoryzacji, myślę.

+0

Dziękuję za szczegółową odpowiedź. Nadal jestem w punkcie, w którym mogę przeprojektować podejście - które wydaje się najlepszą opcją. Może istnieć wystarczająca podobieństwo, aby zgrupować kilka interfejsów, jak wspomniano w poniższym poście. Jeśli nie, może po prostu zrezygnować z interfejsu i upewnić się, że korzystanie z niego jest włączone. – kaledev

5

Jeśli typy, które mają być używane jako argument, są zawsze zmienne, nie widzę powodu, aby używać generycznych. Wystarczy użyć zwykłego obiektu Typ:

public abstract class Item { 
    public abstract void use(Object ... arguments); 
} 

public class Book extends Item { 
    public void use(Object ... arguments) { ... } 
} 
1

Najlepszym podejściem, jakie mogę sobie wyobrazić, jest zgrupowanie elementów zgodnie z ich metodą use().

Przykład

public abstract class QueueableItem { 
    public abstract void use(String, Queue); 
} 

public abstract class OrdinaryItem{ 
    public abstract void use(String); 
} 

Jeżeli zgrupowane elementy mają wspólne zachowanie (częste jak w metodzie samego podpisu & wartość zwrócona), można zdefiniować i rozszerzyć klasę rodzica, który będzie zawierał definicję tego wspólnego zachowanie.

8

To, czego chcesz, to Value Object Pattern.

Zdefiniuj klasę, która zawiera różne typy parametrów w jednym obiekcie wartości , a metoda abstrakcyjna przyjmuje parametr tego typu. Każda zmiana parametrów, które rozważałeś, będzie miała własną klasę wartości.

Następnie wystarczy dodać typ rodzajowy do klasy i mają metody abstrakcyjne zaakceptować parametr tego typu:

public abstract class Item<V> { 
    public abstract void use(V v); 
} 

go używać, załóżmy MyItem potrzebuje obiektu wartość typu MyValueClass:

public class MyItem extends Item<MyValueClass> { 
    public void use(MyValueClass v) { 
    } 
} 
0

Tak, możemy podać parametry metody abstrakcyjnej, ale musimy podać ten sam typ parametrów dla metod, które napisaliśmy w klasach pochodnych.

Powiązane problemy