I am refactoring a base class, implementations of which are plug-ins, loaded at runtime by another class using reflection.
The class I am refactoring uses a user ID of the form domainuser. I need to extend it to also work with domain email addresses.
To do this, I have introduced an enum of user identifier types, e.g UserIdentifierType.DomainUser, UserIdentifierType.SmtpAddress, UserIdentifierType.SomeFutureType
.
In order for the class to work, the user identifier type must be set.
My usual approach would be to create a constructor which takes the required identifier type as an argument but the problem I have is that the class consuming it only knows how to call the empty constructor. It is not feasible to change the consuming class.
Instead, I have implemented an initialising method:
public void Initialise(UserIdentifierType userIdentifierType)
{
_initialised = true;
}
Each method of the base class checks that the initialiser has been called and throws an exception if not.
if(!_initialised){throw new Exception("The Initialise() method must be called before using any other methods of this class");}
To me, that smells worse than my socks! It’s not transparent, it’s not self documenting and doesn’t fit the principles of OOP.
Is there some neater way to accomplish setting the identifier type in the base instance without using a constructor or an initialiser?
4
It sounds like your problem, in short, is that you have to make a backwards-incompatible change to a public class with multiple clients which you do not control.
The usual way to deal with such backwards compatibility issues is not to change the existing code at all. Instead, you provide an entirely new API which implements the new backwards-incompatible functionality and announce that the old class is deprecated.
Now you can gradually cajole your clients into changing their code to use your new class. Once all your users (or at least all the users you care about) are using the new and improved API, you can revoke support for the old class and/or delete it.
This sounds like a lot of work, and indeed it is. For code with lots of clients (frameworks and platforms in particular) it can even take years. But the alternative is breaking all your API clients with no warning, pissing everyone off, losing their business and going bust.