#java #list #collections #queue
#java #Список #Коллекции #очередь
Вопрос:
Класс Java CircularFifoBuffer в пакете org.apache.commons.collections.buffer не является универсальным и может хранить объекты любого класса.
Я хотел бы создать обобщенную версию этого, которая может содержать только объекты класса T. Моей первой мыслью было расширить CircularFifoBuffer и просто написать новый метод ‘add’:
public class CircularFifoQueue<T> extends CircularFifoBuffer {
public boolean add(T data) {
return super.add(data);
}
}
Однако при этом остается старый метод ‘add’, позволяющий добавлять объекты произвольного класса. Есть ли способ обойти это, который использует наследование, а не композицию (чтобы мне не приходилось повторно реализовывать все методы CircularFifoBuffer), но не позволяет пользователям класса добавлять объекты, отличные от T?
Ответ №1:
Одна из идей заключается в том, чтобы реализовать свой собственный буфер, который просто переносит исходный:
public class CircularFifoQueue<T> {
private CircularFifoBuffer buffer = new CircularFifoBuffer();
public boolean add(T data) {
return buffer.add(data);
}
// implement all other methods that are needed
}
Таким образом, внутренний буфер принимает все, но оболочка гарантирует, что могут быть добавлены только объекты T
типа. Проблема: прямо сейчас буфер не реализует никакого интерфейса. Таким образом, его использование сейчас немного ограничено (вы не можете использовать его, если вам нужно отправить Buffer
, например)
Комментарии:
1. Спасибо, это решение, с которым я решил пойти. Я также реализовал
Queue<T>
, чтобы иметь доступ к этим методам. Единственная проблема заключается в том, что я хотел бы, чтобыadd(T t)
метод возвращал объект, который выпадает из конца очереди, а это кажется невозможным в рамкахQueue<T>
интерфейса. На данный момент я только что создал новый методaddAndRetrieve(T t)
, который делает то, что я хочу, хотя мне было бы интересно услышать о других решениях.2. Отличная идея! Я бы также хотел, чтобы CircularFifoQueue реализовал Queue.
Ответ №2:
Нет, вы не можете.
Простая причина, по которой это невозможно, заключается в полиморфизме. Если бы вы могли удалить add(Object)
метод, вы бы нарушили полиморфизм для CircularFifoBuffer
класса.
Вот простой пример. Чтобы это работало правильно, у вашего CircularFifoQueue
класса должен быть add(Object)
метод.
CircularFifoBuffer buffer = new CircularFifoQueue<String>();
buffer.add(new Object());
Комментарии:
1. Хорошо, спасибо. Итак, единственное решение — использовать композицию и повторно реализовать все необходимые методы?
2. Взгляните на шаблон делегирования en.wikipedia.org/wiki/Delegation_pattern Это сработало бы в вашем случае.
Ответ №3:
ответ @Vivien уже объясняет, почему на самом деле это не имеет смысла делать (для получения дополнительной информации прочитайте о принципе подстановки Лискова).
Однако вы могли бы обойти это, определив пользовательское переопределение add(Object)
, которое просто генерирует исключение во время выполнения. Это не очень элегантное решение, но если вы хотите быстро исправить, то это может быть оно.
Ответ №4:
Вы можете попробовать следующий подход. Это не очень элегантно, но оно должно выполнять свою работу:
public class CircularFifoQueue<T> extends CircularFifoBuffer {
private Class<T> klass;
public CircularFifoQueue(Class<T> klass) {
this.klass = klass;
}
@Override
public boolean add(Object data) {
T typedData = klass.cast(data);
return super.add(typedData);
}
public boolean add(T data) {
return super.add(data);
}
}
...
CircularFifoQueue<String> queue = new CircularFifoQueue<String>(String.class);
queue.add("hello"); // should work
queue.add(123L); // should throw ClassCastException
В любом случае, реализовать класс, который делегирует вызовы своих методов, не очень сложно. Любая приличная IDE автоматически сгенерирует это для вас.