1

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 domain\user. 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?

  • the class consuming it only knows how to call the empty constructor” – are you sure there's no way to fix that? If that truly can't be changed, you could put a factory in between the user and your actual class. The loader instantiates a default factory on which your user code calls .Create(identifer) instead of Initialize to get an actual instance. Creating objects in an invalid state is never a good idea. – amon Nov 15 '14 at 15:00
  • @amon Thanks! The consuming class could me modified but it would be a major breaking change in a core product, whereas I am working only in a plug in to it. I do like your suggestion, something like :base.Create(identifier) in the class constructor? – Simon Nov 15 '14 at 15:26
  • Why do you have 3 sorts of IDs rather than mapping the 3 to the already existing ID? – Telastyn Nov 15 '14 at 15:30
  • How is the UserID passed to the class? – Euphoric Nov 15 '14 at 21:10
1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.