I'm using a Singleton-like class to operate session and make the classes to be referenced easily. I have two classes LockPage and HomePage which are lazily initialized. My Singleton-like class is here:
public class Session{
private static LockPage lock;
private static HomePage homePage;
private Session() {
}
public static HomePage getHomePage() {
if(homePage==null) {
homePage = new HomePage();
}
return homePage;
}
public static LockPage getLockPage() {
if(lock==null) {
lock = new LockPage();
}
return lock;
}
public static void resetEverything() {
lock=null;
homePage = null;
}
}
LockPage gets instantiated first from main() and after a successul login, HomePage gets initialized.
On HomePage class if the user clicks logout, this gets called:
public void logOUt(){
Session.getHomePage().disposeScreen();
Session.resetEverything();
Session.getLockPage();
}
I need to use HomePage class in several other classes so I thought referencing like this might be better. Please let me know if this is a GOOD APPROACH or if there is a much better way.
P.S: The Session class is fundamentally not a Singleton
Please let me know if this is a GOOD APPROACH
No, I would argue it's not. You're coupling the code to a specific implement and overtly exposing other parts of the API to tampering, which is beyond the responsibility of the classes using them ... ever had someone call removeAll
on your component before 😱?
Two immediately better solutions come to mind...
This separates the layers of your code into distinct functional groups.
In the context of your question, you would "share"/"expose" the model to all the "views" which needed it. Further, by defining the base model as an interface
, you reduce the coupling and reduce the possibility of views doing things they shouldn't, just because they can (and your design allowed them to).
This is fancy, pancy way of saying "pass stuff" via parameters.
So rather then the view getting it's information from a "centralised" source, like a singleton or creating and configuring their own instances, you pass all the information they need via constructor or method parameters.
With DI, it's easier to reason about the state of the code at any given point in time. It also makes it simpler to test, as you don't need to "prepare" some global state, but instead, simply make the objects you need (such as mocks) and "inject" them into the code.
Again, this is where using interface
s will reduce the coupling, making the API much more flexible and resistant to change.
This is an area around which flame wars are created and it can be quite decisive.
You should have a look at Are Singletons Evil? for a bunch of opinions.
Just beware, some people love them, some people hate, most of the rest us, we just get on with writing code and trying to make our lives easier 😉
As a "general" comment, global state needs to be treated very, very carefully