В настоящее время я нахожусь в процессе разработки иерархии классов для проекта моделирования. Это будет имитация дискретного события дерева Element
экземпляров. Для краткости (и потому что меня интересует только общая часть проблемы), я приведу здесь только наброски классов / интерфейсов, поэтому синтаксис не будет идеальным. Чтобы начать с чего-то, элемент может выглядеть так:
public abstract class Element {
private Set<Element> children = new HashSet<Element>();
public Element getContainer();
public Collection<Element> getChildren() {
return Collections.unmodifiableSet(children);
}
public Position getPosition();
protected void add(Element e) { children.add(e); }
protected void remove(Element e) {children.remove(e); }
}
Определение Position
на самом деле не имеет значения, и то, что должны делать другие методы, самоочевидно, я надеюсь. Чтобы сделать вещи немного интереснее, мы добавляем в пул еще один интерфейс:
public abstract class Solid extends Element {
public Size getSize();
}
Опять же, точное значение Size
не имеет значения, просто предполагается, что Solid
- это физический объект, который заполняет пространство в моделируемом мире. Теперь, когда у нас есть твердый объект, мы можем захотеть сложить их друг на друга, так что вот Stack
:
public abstract class Stack extends Solid {
public void add(Solid s); // <- trouble ahead!
}
И вот тут начинается беда. Я действительно хочу, чтобы в Stack
были добавлены только экземпляры Solid
. Это потому, что трудно сложить объекты без размера, поэтому Stack
потребуется что-то с Size
. Поэтому я переделываю свой Element
, чтобы выразить это:
public abstract class Element<E extends Element<?>> {
private final Set<E> children = new HashSet<E>();
public Element<?> getContainer();
public Collection<E> getChildren();
public Position getPosition();
public void add(E e);
public void remove(E e);
}
Мое намерение здесь состоит в том, чтобы выразить, что Element
может иметь ограничение на то, какие (под) типы Element
могут содержать. Пока это работает и все. Но прямо сейчас я почувствовал необходимость ограничения для контейнера для Element
. Как это выглядит?
public interface Element<E extends Element<?,?>, C extends Element<?, ?>>
Или это выглядит так:
public interface Element<E extends Element<?,C>, C extends Element<E, ?>>
Я начинаю чувствовать себя немного нечетко по этому поводу, и в игре есть еще кое-что:
- должны быть «Порты» (
Input
и Output
), которые переносят Элементы из одного контейнера в другой. Мне тоже придется применить магию дженериков.
- В моем списке задач есть графический редактор для моделей. Поэтому я должен сделать эти проверки доступными также во время выполнения. Поэтому я думаю, что будут литералы типов и что-то вроде
public boolean canAdd(Element<?, ?> e)
, на которое редактор будет полагаться. Поскольку этот метод очень важен, я бы хотел, чтобы он был final
методом класса Element
, поэтому ни один пьяный разработчик не может ошибиться в 4 часа утра.
- Было бы здорово, если бы подклассы
Element
могли бы решить для себя, какой класс Collection
они используют, потому что некоторые из LinkedList
или что-то вроде идеально подходят.
Итак, вот мои вопросы:
- Я заново изобретаю колесо? Какая библиотека делает это для меня?
- Могу ли я решить эту проблему с помощью дженериков? (если ответ да: некоторые советы по реализации очень приветствуются)
- Может быть, это немного перегружено?
- Есть ли лучший заголовок или теги для этого вопроса? : -)
- (просто оставьте здесь свое мнение)