Реализация опакового дескриптора в 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.