Страницы

Поиск по вопросам

воскресенье, 26 января 2020 г.

Паттерн ООП, ограничивающий количество экземпляров класса по аттрибуту

#ооп #многопоточность #шаблоны_проектирования


Как организовать невозможность в программе существования нескольких экземпляров одного
класса с одинаковым значением определенного атрибута? 
Как называется такой паттерн ООП (если он есть)?
Пишу приложение на JAVA, многопоточное, но примеры интересны на различных языках
программирования (естественно с ООП парадигмой).    


Ответы

Ответ 1



В общем случае наиболее подходит под вашу задачу паттерн Factory. В частном случае, когда разрешен всего 1 объект это классический Singleton. Единственное, я бы не стал возлагать на паттерн задачу безопасности ибо что Singleton, что Factory ломаются на раз-два. Update Применительно к Java такой способ ведь действительно существует и часто используется в реальной жизни - например кэширование пула коннектов (например JDBC). Как известно, коннект ресурс достаточно дорогой и ценный и если по ходу пьесы коннект берется во многих местах имеет смысл организовать кэширование коннектов с ограничением количества оных. Вполне аналогично также и ставится ограничение на количество окон в системе. Да в том же Android'е надысь писал такую штуку. Ставится корневой класс - прародителей всех Activity и вперед создавать списочек, контроль все как надо. Так что надо попроще и без кошачьих завихрений, а то совсем ужо замутили головы boost commiter, перегрузка операторов... P.S. Ну вы млин даёте :)

Ответ 2



Эта задачу (если решать ее в общем виде) очень сложно решить хорошо в языках с Garbage Collector'ами в силу недетерминированности работы последних. Под хорошим решением подразумевается что-то типа специальной фабрики ObjectFactoryWithAttributeChecking, в которой хранятся слабые ссылки на объекты выбранных типов, и при попытке создания нового объекта она проверяет, жив ли прошлый / прошлые или нет. Понятно, что, в силу недетерминированности GC очень легко получить ситуацию, когда на объект уже никто не ссылается, но он еще не заколлекчен (и в этот момент фабрика ObjectFactoryWithAttributeChecking будет вести себя некорректно). Плохой подход - вводить такую же фабрику с явными методами Create и Dispose - решает задачу, но сводит на нет преимущества автоматической сборки мусора и крайне неустойчив. Если calling site в случае такого подхода забудет вызвать Dispose, то ваша фабрика моментально оказывается в неконсистентном состоянии. Если задача поставлена из соображений отладки, то самый верный путь решения заключается в инжектировании своего кода в аллокатор на низком уровне. .NET, например, допускает такие штуки для решения задач профайлинга, но, в случае выбора такого подхода каждый кейс нужно рассматривать индивидуально. В случае языков без сборки мусора (типа C++) вроде как можно реализовать решение на уровне собственного аллокатора, но сделать это правильно для всех кейсов крайне нетривиально. Такая задача должна быть по зубам разработчиками уровня boost commiter, да и то, наверняка, не всем. Небольшой Update: Сейчас еще раз перечитал вопрос и, в принципе (если вас устроит такой подход), вы можете просто сделать фабрику ленивых синглтонов - т.е фабрику с методом getObjectWithSomeConcreteAttribute, которая будет создавать объект с таким атрибутом только один раз по его первому запросу. Создание объектов в обход фабрики в таком случае, разумеется, надо запретить. Другое дело, что это не слишком интересно, если сравнивать с задачей, решения для которой я предлагаю выше :)

Ответ 3



Есть такой вариант решения "проблемы", недостатки такого подхода очевидны, хотя вариант имеет право на жизнь (видел в нескольких enterprise продуктах): public enum TestEnum { INTEGER { @Override public void doAction(Object arg) { if (arg instanceof Integer) { System.out.println("int - " + arg); } } }, STRING { @Override public void doAction(Object arg) { if (arg instanceof String) { System.out.println("str - " + arg); } } }, BOOLEAN { @Override public void doAction(Object arg) { if (arg instanceof Boolean) { System.out.println("bool - " + arg); } } }; public abstract void doAction(Object arg); public static void applyAction(Object arg) { System.out.println("Handling: '" + arg + "'"); for (TestEnum e : values()) { e.doAction(arg); } } public static void main(String args[]) { List objects = new LinkedList(); objects.add("ab"); objects.add(Integer.valueOf(1)); objects.add("cd"); objects.add(Integer.valueOf(2)); objects.add(Boolean.valueOf(true)); objects.add(Integer.valueOf(3)); objects.add("ef"); for (Object object : objects) { TestEnum.applyAction(object); } } }

Комментариев нет:

Отправить комментарий