How to organize the impossibility in the program of the existence of several instances of one class with the same value of a certain attribute? What is the name of such an OOP pattern (if any)? I am writing an application on JAVA, multi-threaded, but examples are interesting in various programming languages (of course, with the OOP paradigm).
- Overload the operator new and insert the corresponding check there. - igumnov
- one@igumnov I would like to see this. - Costantino Rupert
- @ Kotik_hochet_kushat Well, if inside the body of the new, apart from the size, you submit a link to the global object that stores information about the created instances of the other classes (and update this information in the same place), then it is theoretically possible. Although I have never done such a thing, so I can’t say exactly what pitfalls can be. - igumnov
- @ Kotik_khohet_kush So probably you can attach an automatic bicycle garbage collection with a strong desire. PS I mean C ++, not Java, of course, and by attribute I mean just the value of a member of a class. - igumnov 1:16
- @irockez is probably the easiest way to do a self-diagnostic method in the object, which returns either null or this. Those. create (or change attribute) and immediately call this method. - avp
3 answers
In general, the Factory pattern is most suitable for your task. In the particular case where only 1 object is allowed, this is a classic singleton. The only thing I would not do is entrust the security task to the pattern because Singleton and Factory break down once or twice.
Update
With regard to Java, this method actually exists and is often used in real life — for example, connection pool caching (for example, JDBC). As you know, a connection resource is quite expensive and valuable, and if during the play a connection is taken in many places, it makes sense to organize caching of connections with a limited number of them.
Quite similarly, a limit is also placed on the number of windows in the system. Yes, in the same Android, nadys wrote such a thing. The root class is put - the ancestors of all the Activity and go ahead to create a list, control everything as it should.
So it should be simpler and without feline twists, and then they just muddled the heads of the boost commiter
, operator overload ...
PS Well, you give Mlyn :)
- This task (if solved in general) is very difficult to solve well in languages with
Garbage Collector'ами
due to the non-determinism of the latter’s work.
A good solution implies something like a special
ObjectFactoryWithAttributeChecking
factory, which stores weak references to objects of selected types, and when trying to create a new object, it checks whether the past / past is alive or not.It is clear that, due to the non-determinism of the
GC
very easy to get a situation where no one refers to the object, but it is not yet tricky (and at this point theObjectFactoryWithAttributeChecking
factory will behave incorrectly).
- A bad approach — introducing the same factory with explicit
Create
andDispose
methods — solves the problem, but negates the advantages of automatic garbage collection and is extremely unstable.
If the
calling site
in the event of such an approach, forgets to callDispose
, then your factory is instantly in a non-consistent state.
- If the task is set for debugging reasons, then the most correct solution is to inject your code into the allocator at a low level.
.NET
, for example, allows such things to solve profiling problems, but in the case of choosing such an approach, each case must be considered individually.
- In the case of languages without garbage collection (like
C++
), it seems like you can implement a solution at the level of your own allocator, but it is extremely nontrivial to do this correctly for all cases . Such a task should beboost commiter,
tough for developers at the level of theboost commiter,
and even then, probably, not for everyone.
Small Update:
- Now I re-read the question and, in principle (if you are satisfied with this approach), you can simply make a lazy Singleton factory — that is, a factory with the
getObjectWithSomeConcreteAttribute
method that will create an object with this attribute only once upon its first request.
Creating objects around the factory in this case, of course, should be prohibited.
- Another thing is that it is not very interesting when compared with the task for which I offer solutions above :)
- Hmm ... if the
ObjectFactoryWithAttributeChecking
factory will hold references to objects, how do they get under the garbage collection rink? Or am I missing something? - Barmaley - @Barmaley Well, weak links do not affect the garbage collection process. - Costantino Rupert
- @ Kotik_khohet_kushat and what prevents to keep normal links? - Barmaley
- @Barmaley - See, I proposed solutions for two similar problems, one of which is an order of magnitude more complicated. - A simple task: to find a convenient way to access an object (or several objects), the lifetime of which coincides with the time of the application, provided that the instance can have only one instance. - This problem is solved by what is written in you or in the second part of my answer - by the factory, which creates objects and does not release references to them. - Costantino Rupert
- - Difficult task: to do the same, but so that, say, you can create no more than five instances of the same object, and that their lifetime is determined solely by the presence of references to them without using the
Disposable.
patternDisposable.
- That is, while you can reach up to 5 objects, do not allow to create another one. So, in the context of this task, I concluded that the correct behavior cannot be achieved without injecting into the allocator and other pleasant things. - It is clear that the use of ordinary (not weak) links in this case is meaningless. - Costantino Rupert
There is such a solution to the "problem", the disadvantages of this approach are obvious, although the option has the right to life (seen in several enterprise products):
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<Object> objects = new LinkedList<Object>(); 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); } } }