To understand the proper way to workaround Singletons, you need to understand what is wrong with Singletons (and global state in general):
Singletons hide dependencies.
Why is that important?
Because If you hide the dependencies you tend to lose track of the amount of coupling.
You might argue that
void purchaseLaptop(String creditCardNumber, int price){
CreditCardProcessor.getInstance().debit(creditCardNumber, amount);
Cart.getInstance().addLaptop();
}
is simpler than
void purchaseLaptop(CreditCardProcessor creditCardProcessor, Cart cart,
String creditCardNumber, int price){
creditCardProcessor.debit(creditCardNumber, amount);
cart.addLaptop();
}
but at least the second API makes it clear exactly what the method's collaborators are.
So the way to workaround Singletons is not to use static variables or service-locators, but to change the Singleton-classes into instances, which are instantiated in the scope where they make sense and injected into the components and methods that need them. You might use a IoC-framework to handle this, or you might do it manually, but the important thing is to get rid of your global state and make the dependencies and collaborations explicit.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…