Nie można tego zrobić bezpośrednio w jednej klasie, ponieważ poniższa definicja klasy nie może zostać skompilowana z powodu usunięcia typów ogólnych i zduplikowanej deklaracji interfejsu.
class TwoTypesConsumer implements Consumer<Apple>, Consumer<Tomato> {
// cannot compile
...
}
Każde inne rozwiązanie pakowania tych samych operacji konsumpcji w jednej klasie wymaga zdefiniowania Twojej klasy jako:
class TwoTypesConsumer { ... }
co jest bezcelowe, ponieważ musisz powtórzyć / powielić definicję obu operacji i nie będzie do nich odwołań z interfejsu. IMHO robienie tego jest złym, małym i duplikatem kodu, którego staram się uniknąć.
Może to wskazywać również na to, że w jednej klasie jest zbyt duża odpowiedzialność za zużywanie 2 różnych obiektów (jeśli nie są one połączone).
Jednak to, co robię i co możesz zrobić, to dodać jawny obiekt fabryki, aby utworzyć połączonych konsumentów w następujący sposób:
interface ConsumerFactory {
Consumer<Apple> createAppleConsumer();
Consumer<Tomato> createTomatoConsumer();
}
Jeśli w rzeczywistości te typy są naprawdę sprzężone (powiązane), to polecam stworzyć implementację w taki sposób:
class TwoTypesConsumerFactory {
// shared objects goes here
private class TomatoConsumer implements Consumer<Tomato> {
public void consume(Tomato tomato) {
// you can access shared objects here
}
}
private class AppleConsumer implements Consumer<Apple> {
public void consume(Apple apple) {
// you can access shared objects here
}
}
// It is really important to return generic Consumer<Apple> here
// instead of AppleConsumer. The classes should be rather private.
public Consumer<Apple> createAppleConsumer() {
return new AppleConsumer();
}
// ...and the same here
public Consumer<Tomato> createTomatoConsumer() {
return new TomatoConsumer();
}
}
Zaletą jest to, że klasa fabryczna zna obie implementacje, istnieje stan współdzielony (w razie potrzeby) i w razie potrzeby można zwrócić więcej połączonych konsumentów. Nie ma powtarzającej się deklaracji metody konsumpcji, która nie pochodzi z interfejsu.
Należy pamiętać, że każdy konsument może być niezależną (nadal prywatną) klasą, jeśli nie jest w pełni spokrewniony.
Wadą tego rozwiązania jest złożoność wyższej klasy (nawet jeśli może to być jeden plik java) i aby uzyskać dostęp do metody consume, potrzebujesz jeszcze jednego wywołania, więc zamiast:
twoTypesConsumer.consume(apple)
twoTypesConsumer.consume(tomato)
ty masz:
twoTypesConsumerFactory.createAppleConsumer().consume(apple);
twoTypesConsumerFactory.createTomatoConsumer().consume(tomato);
Podsumowując, możesz zdefiniować 2 ogólnych konsumentów w jednej klasie najwyższego poziomu przy użyciu 2 klas wewnętrznych, ale w przypadku wywołania musisz najpierw uzyskać odniesienie do odpowiedniego konsumenta implementującego, ponieważ nie może to być po prostu jeden obiekt konsumenta.