Реализация опакового дескриптора в Java

Я хочу реализовать непрозрачный дескриптор в Java.

то есть когда пользователь вызывает Create для моего класса Factory, я создаю объект класса, но не возвращаю сам объект, а int, представляющий экземпляр класса. У меня будет HashMap который будет хранить int как ключ и объект как значение. Каждый другой метод класса примет int как один параметр, и он получит объект из HashMap и выполнить необходимую операцию над соответствующим объектом. Будет метод удаления, который удалит его из HashMap и позвольте этому быть сборщиком мусора.

Мне было интересно, есть ли какая-либо существующая структура класса / данных, которая позволит мне избежать реализации дескрипторной части кода?

Я не думаю, что я могу использовать hashCode или же identityHashCode как уникальный идентификатор, потому что они не гарантированно будут уникальными.

Если я сам реализую счетчик хода, мне придется решать такие проблемы, как безопасность потоков, при создании уникального идентификатора, повторное использование идентификаторов при удалении объекта из hashMap и т.д. Поэтому мне было интересно, есть ли какой-нибудь существующий класс, который может помочь с этим.

4 ответа

Решение

Давайте сделаем простые вычисления. Вы сказали, что у вас будет максимум 10000 объектов, максимум 1 час жизни. Давайте предположим более жесткие условия - 10000 объектов в 1 минуту. 32-разрядное целое число будет достаточно примерно на 1 год. Более того, даже если целое число переполняется, оно снова начинается с нуля, повторно используя целые числа, использованные 1 год назад. Как я вижу, этого более чем достаточно. Так что, просто используйте AtomicInteger, он работает очень быстро и более чем достаточно для ваших требований.

Если у вас все еще есть сомнения, у вас может быть более гибкое решение - когда генерируется новый дескриптор, сначала проверьте, есть ли у этого HashMap этот ключ (это очень быстрая операция), если он есть, просто выберите следующее целое число. Это похоже на https://superuser.com/questions/135007/how-are-pids-generated в операционных системах.

Возьмите длинное значение как id. У тебя никогда не кончатся длинные вещи. Использование int вносит большую сложность и замедляет работу.
написать get() set() и increment() с использованием syncronized (или объекта частной блокировки) очень просто. В противном случае используйте AtomicLong с incrementAndGet()

Я бы держал свой счетчик. Используйте AtomicInteger, если вы беспокоитесь о безопасности потоков.

И я бы не стал повторно использовать идентификаторы: это очень затруднит отладку и ведение журнала. У вас вряд ли закончатся целые числа.

Я предлагаю вам использовать базовый дизайн ОО, который возвращает инкапсулированный объект - он простой, мощный и хорошо известный.

Не возвращайте int с фабрики и передавайте его фабричным методам. Вместо этого объявите определенный класс для вновь созданного объекта (абстрактный тип данных) и верните экземпляр этого класса ADT. Переместите методы, которые работают с вашим объектом, с фабрики в класс ADT.

Например

// file Widget.java
package com.company.widgets;

public class Widget {
    String widgetName;
    String widgetType;
    int widgetCode;

    // By making the constructor "protected", can stop arbitrary classes from 
    // constructing and ensure on the WidgetFactory can construct
    protected Widget(String widgetName,
                    String widgetType,
                    int widgetCode) {
         this.widgetName = widgetName;
         this.widgetType = widgetType;
         this.widgetCode = widgetCode;
    }

    public boolean equals(Object other) {
         ...
    }

    public int hashcode() {
         ...
    }

    public void widgetOperation1(String fred) {
        ...
    }

    public String widgetOperation2(int barney ) {
        ...
    }
}

//========================================================

// file WidgetFactory.java
package com.company.widgets;

public class WidgetFactory {
    // Member attributes as needed. E.g. static Set of created Widget objects
    private static Set<Widget> widgetSet;
    static { widgetSet = new HashSet() }

    // 
    public static Widget createNewWidget() {
        Widget widget = new Widget();
        widgetSet.add(widget);
        return widget;
    }

    public static removeWidget(Widget widget) {
        widgetSet.remove(Widget)
    }
}

Обратите внимание, что 1000 объектов не так много, поэтому это решение будет эффективным. Если вам действительно нужно оптимизировать каждую микросекунду производительности, у вас есть возможность сделать фабрику умнее, чтобы виджеты не удалялись, а перерабатывались - например, у вас может быть два набора: widgetsInUseSet и widgetsRecycledSet.

Другие вопросы по тегам