В своей работе я наткнулся на такой вопрос дизайна:
- Мне нужен один экземпляр
Manager
класса на поток
- Эти экземпляры должны быть доступны глобально, как в шаблоне синглтона через статическую функцию
- Каждый поток может нуждаться в инициализации своего экземпляра с разными аргументами
- Время жизни этих экземпляров должно контролироваться, иногда было бы полезно удалить экземпляр и позволить GC собрать его
Первые две точки сделали бы это «синглтоном на поток», если такая вещь существует.
Вот что я придумал (код упрощен, я пропустил проверки безопасности и т. Д.):
public class Manager {
private final static ThreadLocal<Manager> local = new ThreadLocal<Manager>();
private int x;
Manager(int argument) { x = argument; }
public static void start(int argument) { local.set(new Manager(argument); }
public static void clean() { local.remove(); }
private void doSomething1() { x++; .... }
private int doSomething2() { if (--x == 0) clean(); ... }
public static void function1() { local.get().doSomething1(); }
public static int function2() { return local.get().doSomething2(); }
}
Как видите, функция clean также может вызываться из закрытых методов.
Также обратите внимание, что благодаря использованию статических функций ссылка на экземпляр никогда не просачивается, поэтому экземпляры, назначенные различным потокам, не будут смешиваться.
Это работает вполне нормально, но потом я получил другое требование:
- Разные потоки могут использовать разные реализации класса Manager
Итак, я определил интерфейс:
public interface ManagerHandler {
void method1();
int method2();
}
И модифицировал Manager
класс:
public class Manager {
private final static ThreadLocal<ManagerHandler> local = new ThreadLocal<ManagerHandler>();
public static void start(int argument) {
ManagerHandler handler;
// depending on the context initialize handler to whatever class it is necessary
local.set(handler);
}
public static void clean() { local.remove(); }
public static void function1() { local.get().method1(); }
public static int function2() { return local.get().method2(); }
}
Пример реализации будет выглядеть так:
public class ExampleManagerImplementation implements ManagerHandler {
private int x;
public ExampleManagerImplementation(int argument) { x = argument; }
public void method1() { x++; .... }
public int method2() { if (--x == 0) Manager.clean(); ... }
}
Класс менеджера работает здесь как фасад, перенаправляя все вызовы соответствующему обработчику. У этого подхода есть одна большая проблема: мне нужно определить все функции как в классе Manager
, так и в интерфейсе ManagerHandler
. К сожалению, класс Manager
не может реализовать интерфейс ManagerHandler
, потому что он имеет статические функции, а не методы.
Вопрос в том, можете ли вы придумать лучший / более простой способ достижения всех целей, перечисленных выше, которые были бы свободны от этой проблемы?