3

What is best practice to restrict instantiation of the classes to only one class? Something like this but in Java.

Let's say there is Main class, then there are User, Admin, View, Data, Client etc. classes. Only 'Main' class should be able to instantiate all other classes.

So if 'User' need to call 'getUser' method in 'Data' class, it can't instantiate 'Data' class and call method, but it has to call 'Main' class, and then 'Main' will instantiate 'Data' class and pass arguments to its 'getUser' method.

What I am thinking is using private constructor, Factory Pattern etc., but not sure if this will result in what I need. Due to the complexity I don't think inner classes would be good solution.

Any advice on this?

Nenad Bulatović
  • 7,238
  • 14
  • 83
  • 113
  • 2
    Do you want a guarantee that the classes can never be instantiated by a class other than the Main, or is this more of a practice thing where you don't pollute the namespace? If the second, you could make the constructors for classes other than Main package private and ensure these are all in their own package? – adickinson May 07 '19 at 09:10
  • 2
    This is what packages in Java are for. You can make things package-private (which is actually default when you don't say public), and then code in other packages cannot access it. This way, you can keep the constructors (or even the whole class) hidden from user code and internal to your own implementation. – Thilo May 07 '19 at 09:14
  • 2
    I can't see a good reason for wanting to do this. This seems like a great way to achieve a lot of complexity for not much benefit (and likely a fair amount of detriment). – Ant P May 07 '19 at 09:19
  • @adickinson yes, I want guarantee that the classes can never be instantiated by a class other than the Main. Yes, I can make constructor for the classes are private and all classes are in separate packages. – Nenad Bulatović May 07 '19 at 09:20
  • make all the constructors protected, and provide one factory with public methods – Stultuske May 07 '19 at 09:29
  • @NenadBulatovic No, subpackages do not work that way. All your code has to be in the same package for package-private to work. The idea is to hide implementations from users of your code, not from yourself. – Thilo May 07 '19 at 09:42
  • @NenadBulatovic: [this](https://stackoverflow.com/questions/515269/factory-pattern-in-c-how-to-ensure-an-object-instance-can-only-be-created-by-a) question that you have linked is about preventing an object from being initialized, unless through the factory... what you are asking is about creating a "universal factory" for creating all types of objects... in my opinion, a "universal factory" is not a good approach... as the application grows, your "universal factory" starts doing too much work. this would violate SRP and potentially OCP. – Hooman Bahreini May 08 '19 at 08:00

3 Answers3

3

A distinct answer on the conceptual level (as there are already good answers on the technical "how to do it"):

Let's say there is Main class, then there are User, Admin, View, Data, Client etc. classes. Only 'Main' class should be able to instantiate all other classes.

I don't think this is a good starting point. Of course, when one follows Domain Driven Design, using factories is well established.

But there is one subtle point to add: you still want to cut your "boundaries" in reasonable ways. Meaning: don't force all objects into a single factory. Your objects should somehow resemble their domains, and be separated where needed.

Meaning: using factories is fine, but don't force yourself into the wrong corner by enforcing that there is exactly one factory that is supposed to handle all kinds of objects you deal with. Instead: try to reasonably partition your object model, and have as many factories as it makes conceptually sense to have.

Also note that you probably should distinguish between objects that mainly provide data/information, and "behavior" on the end. Thus it might be worth looking into the idea of having a service registry (for example what you do with the netflix Eureka framework, see here).

And finally, to quote an excellent comment given by tucuxi here: For small applications, factories are over-engineering. For larger applications, I find it questionable to have a single factory called "Main", instead of splitting responsibilities in a more orthodox way.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 2
    This is (currently) the only answer which addresses whether a question on "best practice" is actually referring to a something that is "good practice". For small applications, factories are over-engineering. For larger applications, I find it questionable to have a single factory called "Main", instead of splitting responsibilities in a more orthodox way. – tucuxi May 07 '19 at 10:30
  • @tucuxi I like your comment. So much that I added it to my answer ;-) ( will be showing my appreciation elsewhere) – GhostCat May 07 '19 at 11:05
1

You can use a subclass with a private constructor: With this, only InstantiatonClass can create InstantiatonClass.ArgClass and the constructor of ProtectedClass.

public class ProtectedClass{
    //constructor that can only be invoked with an instance of ArgClass 
    public ProtectedClass(InstantiatonClass.ArgClass checkArg){}
}
public class InstantiatonClass{
    public static class ArgClass{
    //constructor that can only be invoked from InstantiatonClass
        private ArgClass(){}
    }
}
dan1st
  • 12,568
  • 8
  • 34
  • 67
1

You should be able to get caller's class in a Class's constructor:

How to get the name of the calling class in Java?

Then in the classes where you only want to be instantiated by Main, simply check the caller class is Main in its constructor, if not throw a RuntimeException.

Antony Ng
  • 767
  • 8
  • 16