Какой мой лучший подход к этой простой иерархической проблеме Java? - PullRequest
0 голосов
/ 27 мая 2010

Во-первых, я прошу прощения за заголовок вопроса, но я не могу придумать лучшего, чтобы описать мою проблему. Не стесняйтесь менять его:)

Допустим, у меня есть этот абстрактный класс Box, который реализует пару конструкторов, методов и прочего для некоторых частных переменных. Тогда у меня есть пара подклассов, таких как BoxA и BoxB. Оба они реализуют дополнительные вещи.

Теперь у меня есть другой абстрактный класс Shape и несколько подклассов, таких как Square и Circle.

Для BoxA и BoxB мне нужен список объектов Shape, но я должен убедиться, что только Square объекты попадают в список BoxA и только Circle объекты в список BoxB.

Для этого списка (в каждой ячейке) мне нужен метод get() и set(), а также методы addShape() и removeShape().

Еще одна важная вещь, которую нужно знать, это то, что для каждого созданного блока, либо BoxA или BoxB, каждый соответственно Shape список точно такой же. Допустим, я создаю список из Square с именем ls и двумя BoxA объектами с именами boxA1 и boxA2. Независимо от того, что boxA1 и boxA2 должны иметь одинаковый список ls.

Это моя идея:

public abstract class Box {
    // private instance variables

    public Box() {
        // constructor stuff
    }

    // public instance methods
}

public class BoxA extends Box {
    // private instance variables

    private static List<Shape> list;

    public BoxA() {
        // constructor stuff
    }

    // public instance methods

    public static List<Square> getList() {
        List<Square> aux = new ArrayList<Square>();

        for(Square s : list.values()) {
            aux.add(s.clone()); // I know what I'm doing with this clone, don't worry about it
        }

        return aux;
    }

    public static void setList(List<Square> newList) {
        list = new ArrayList<Square>(newList);
    }

    public static void addShape(Square s) {
        list.add(s);
    }

    public static void removeShape(Square s) {
        list.remove(list.indexOf(s));
    }
}

Поскольку список должен быть одинаковым для этого типа объекта, я объявил его как static, и все методы, работающие с этим списком, также static. Теперь, для BoxB класс будет почти таким же в отношении материала списка. Я бы только заменил Square на Triangle, и проблема была решена. Таким образом, для каждого созданного объекта BoxA список будет только один и тот же. То же самое будет происходить с каждым BoxB созданным объектом, но с разным типом списка, конечно.

Итак, в чем моя проблема, спросите вы? Ну, мне не нравится код ... Методы getList(), setList(), addShape() и removeShape() в основном повторяются для BoxA и BoxB, только для типа объектов, перечисленных в списке будет держать это по-другому. Я хотел как-то избежать всех этих методов "дублирования".

Я не могу придумать, как сделать это в суперклассе Box. Попытка сделать это статически, используя Shape вместо Square или Triangle, не будет работать, потому что список будет только один для всех объектов BoxA и BoxB, и мне нужно, чтобы он был только один, но для каждого подкласса Box.

Как я мог сделать это по-другому и лучше?

П.С .: Я не могу описать свой реальный пример, потому что я не знаю правильных слов на английском для того, что я делаю, поэтому я просто использовал пример с рамкой и формами, но он в основном тот же.

1 Ответ

1 голос
/ 28 мая 2010

Вы можете попробовать что-то вроде:

abstract class Box<E extends Shape> {

    abstract protected List<E> getList();

    abstract protected void setList(List<E> list);

    protected static <T extends Shape> List<T> getCommon(Box<T> box) {
        List<T> aux = new ArrayList<T>();
        for (T s : box.getList()) {
            aux.add((T) s.clone());
        }
        return aux;
    }

    protected static <T extends Shape> void setCommon(Box<T> box, List<T> newList) {
        // do something on newList here if needed as common functionality
        box.setList(new ArrayList<T>(newList));
    }
}
class BoxA extends Box<Square> {
    private static List<Square> list;

    @Override
    protected List<Square> getList() {
        return list;
    }

    @Override
    protected void setList(List<Square> list) {
        this.list = list;
    }

    public static List<Square> get() {
        return getCommon(new BoxA());
    }

    public static void set(List<Square> newList) {
        setCommon(new BoxA(), newList);
    }
}

Это немного хакерски, но позволяет вам использовать родительский класс для хранения некоторых общих функций. Вам все равно нужно будет иметь заключительные методы в дочерних классах, но все, что вы делаете в них, - это вызываете родительские методы, давая им новый экземпляр вашего текущего класса, чтобы родительский метод мог вывести из этого универсальный тип. Обратите внимание, что getList() и setList() не являются статичными, чтобы позволить им иметь параметр типа Box, и они защищены, поэтому они не видны снаружи. Они действуют как установщик-получатель для частной статической переменной (которую должен иметь каждый расширяющий класс), чтобы предоставить доступ родителю для выполнения общей работы над переменной, которая принадлежит дочерним элементам.

В методах get() и set() используется new BoxA() (или new BoxB()), чтобы разрешить доступ к статическому списку, а также передать параметр типа родительскому элементу. Поскольку список статичен, не имеет значения, какой экземпляр его возвращает. Обычные методы имеют собственный параметр типа, который не является классом; на самом деле вы можете позвонить по номеру getCommon(new BoxB()) из BoxA, поэтому ваша задача - убедиться, что вы звоните правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...