The disadvantages are the inefficiency of the extra indirection, as you pointed out, and the fact that the compiler doesn't enforce it. All it takes is your worst programmer using one unencapsulated reference to destroy the benefits.
Also, the right way to solve a null pointer problem isn't to replace it with a non-null default value with essentially the same characteristics. The problem with null pointer dereferences isn't that they cause a segfault. That's just a symptom. The problem is that the programmer might not always handle an unexpected default/uninitialized value. That problem still must be handled separately with your self-encapsulation pattern.
The right way to solve a null pointer problem is to not create the object until a semantically valid non-null value can be put into the attribute, and to destroy the object before it is necessary to set any of its attributes to null. If there is never the possibility for a pointer to be null, there is never a need to check it.
Usually when people think an attribute must be null, they are trying to do too much in one class. It often makes the code much cleaner to split it into two classes. You can also split functions to avoid null assignments. Here's an example from another question where I refactored a function to avoid a problematic null assignment.
You have to use the right tool for the right problem. MVC is used to separate the representation logic from routing request logic (controller) and business logic (the model).
For creating objects you should use Creational Patterns. Now, in my opinion,
If I initialize the xml attributes (reading and converting to class
objects), I'm effectively doing things in the model class that the
controller should be doing, which is definitely not good.
It's good if the classes are used by the model.
If I put the initialization method in a controller class, I would have
to refer to a controller class from a model class, which does not
conform to the MVC design.
Yep, don't do this because a low lever layer should not depend of a higher layer.
If I put the whole singleton in controller, then I'd have to look for
the hashmap in the controller package, which defeats the purpose of
having model classes.
This singleton is not a controller so don't do that too.
I can't pass a premade hashmap to the singleton as a parameter
neither, because the constructor is private.. Well, I technically
could, by giving it to the getInstance() method as a parameter, but it
feels like a dirty way of fixing, since I now either pass null every
time, or make another getInstance() method that doesn't accept a
parameter.
Yep, you will break encapsulation here because the hash map is an invariant of your class and if you accept a hash map it means that the invariant can be overwritten, maybe accidentally.
In my opinion this singleton is some kind of factory that provides classes, if the classes are used by the model, then put this singleton in your model package. also take a look at Spring, it will do this for you in a nice way.
Best Answer
If you're limiting yourself to a single method call then I can't honestly imagine a parameterless solution that distinguishes between retrieving the cached value and a reinitialized value.
Every cache I've seen uses one of the following patterns:
An
Invalidate
orExpire
method that flags the value for reinitialization on the next lookup;A boolean or enumeration parameter, such as the one you've ruled out;
A separate reinitialization method, i.e.
getNewCollection
.I do think it must be the Java in you talking, because in other languages I'm very much accustomed to passing parameters in cache lookups - in some cases one of the parameters may even be an anonymous method or function pointer telling the cache how to get the value.
When designing a cache based on deferred initialization, you'll almost certainly also want to have method overloads that take parameters for priority and/or expiration, since there's no longer any
Put
orStore
method to hold them. So, I think the notion of a parameterless lazy-loaded lookup method with optional refresh is pretty much out the window.If you're uncomfortable with it being a getter, then just give it a different name like
Load
orLookup
.P.S. I realize you may not actually be designing a cache here, but the principles still apply; you don't want to have something that acts like a cache internally but doesn't provide cache semantics. That would just lead to headaches.