views:

133

answers:

6

I need to be able to conditionally execute a method. I prefer not having a bunch of IF statements throughout my code for several reasons, the most notable is that at a certain point in the future the method will no longer be used.

I am not sure of the best way to do this or what pattern(s) I should choose to accomplish this task.

The application I refer to is an application that is going to replace a legacy system. The legacy code will be turned off and no longer used at some point. Once that point of time comes, I don't want to have to go back and change any code (if at all possible).

The following is a fictious conceptual example in psuedo of what I mean:

NewSystemEmployee.Save(Employee e)

if (Legacy System Is Running)
{
    LegacySystemEmployee.Save(Employee e)
}

The method NewSystemEmployee.Save always needs to execute. I only want to execute LegacySystemEmployee.Save as long as the Legacy system is running. Once the Legacy system is shutdown, I no longer want to execute LegacySystemEmployee.Save

Once the legacy system goes away, I don't know how I can accomplish what I want without:

  1. Creating an IF statement before I call LegacySystemEmployee.Save OR
  2. Removing every call to LegacySystemEmployee.Save method OR
  3. Changing LegacySystemEmployee.Save method so that it is a stub and nothing more

I also have a requirement that the NewSystemEmployee class does not refer in any way to the LegacySystemEmployee class.

Any suggestions?

Thanks so much

A: 

Aspects will help you, you can inject some behavior before/after your method from external code. Don't know what technology you work in, so you need to look for suitable implementation of AOP on your own.

A.
Sorry, I am working with ASP.NET and C#
mikener
+6  A: 

At first glance this calls for the Strategy pattern (or in fact Template Method), possibly with a Factory Method to control which strategy to use. Example (in pseudo-Java):

class Saver {
    protected void LegacySave(Employee e)  {}
    public final void Save(Employee e) {
        NewSystemEmployee.Save(e);
        LegacySave(e);
    }
}

class LegacySaver extends Saver {
    protected void LegacySave(Employee e) {
        LegacySystemEmployee.Save(e);
    }
}

Since at some point in time you will no more need the legacy call, it makes sense to implement the default LegacySave as empty. Then you can trivially use the class like this:

getSaver().save(employee);

where getSaver() is the factory method which silently decides which Saver implementation to present to its caller. Trivially it can get the class name from a config file.

Question is, how do you need to change the behaviour: runtime, or by restarting the application? If you can restart the application, it is easy to change that one line in the configuration which controls the strategy to use. Changing behaviour on-the-fly is slightly more tricky, but doable.

A lot depends on what programming language you use. E.g. in Java / C++ / C# you can easily accomplish what you want with dependency injection; in some other languages it might not be that easy.

Péter Török
Chain of Responsiblity or Strategy would work here.
fuzzy lollipop
Yes, I plan re starting the application.
mikener
Peter, this looks like a very good way to implement what I need. I have a slightly different way to do this. The code below is c#<pre>class Saver { public void Save(Employee e) { NewSystemEmployee.Save(e); } } class LegacySaver : Saver { public void Save(Employee e) { base.Save(e); // NewSystemEmployee LegacySystemEmployee(e); } } The factory would still determine which Saver implementation to use.I was wondering what you thought of the method I came up with? Do you see any problems?Thanks
mikener
Sorry for the poor formatting of the code. I had a problem when I saved what I wrote. There are two differences between the code you wrote and the code I (mis) posted. 1. The Saver class made no reference to the LegacySave method. 2. The LegacySaver class called both the NewSystemEmployee.Save and the LegacySystemEmployee.Save method. Do you forsee any problems with the methodology I came up with? Thanks
mikener
@mikener The differences are only minor, both solutions work. Yours has the extra benefit that once you get rid of LegacySaver, you won't need to touch Saver again. My case is more robust in general (because subclasses can't forget to call the base class method in the overridden save() ), but I guess in this case, with a single temporary subclass, you may not need this robustness. OTOH in my solution you would have to remove Saver.LegacySave() after removing LegacySaver.
Péter Török
I too vote for strategy pattern in such a scenario.
Kangkan
@Peter - Thanks so much for the help. This is the first time I used StackOverflow. It won't be my last. Thanks
mikener
@mikener Glad to hear that I could help. I made your day, you made mine :-)
Péter Török
A: 

I think that the most appropriate pattern to your situation is a combination of strategy design pattern & factory method design pattern

In your code, don't reffer to the legacy/new algorithm, but to the strategy interface. You will retrieve the interface using the factory method you have.

If you are using Java/C#, you can use IoC tool, like Unity or spring instead/ in addition to your factory

sagie
+1  A: 

I would suggest either the Strategy Pattern, or the Template Method Pattern.

Some links:

Strategy pattern - Wikipedia Article

Strategy Pattern - SourceMaking Website - includes some great examples.

Template Method - Wikipedia Article

Template Method - SourceMaking Website

CraigTP
A: 

I'd go with simple proxy that looks like the legacy system, but checks whether it's running and delegates the action to it in that case:

class LegacySystemEmployeeProxy {
    public Save(Employee employee) {
        if (Legacy System Is Running) {
            LegacySystemEmployee.Save(employee)
        }
    }
}

Now your original code reduces to:

NewSystemEmployee.Save(employee)
LegacySystemEmployeeProxy.Save(employee)

When the legacy system goes away, you can change LegacySystemEmployeeProxy.Save to an empty method.

Antti Sykäri
A: 

Well two solutions come immediately to my mind:

  • Use conditional comppillation if that is available, e.g. (C#)
#if (legacy)
   LegacySystemEmployee.Save(Employee e)
#endif
  • Create a new method SaveEmployee, e.g. (c#)
public static SaveEmployee(Employee e) {
    NewSystemEmployee.Save(Employee e)

    if (Legacy System Is Running) { LegacySystemEmployee.Save(Employee e) }
}

In extension to that you could create a "service interface" that encapsulates all methods that call both systems. And obviously you could combine methods into one, e.g. (C#)

public static SaveEmployee(Employee e) {
    NewSystemEmployee.Save(Employee e)

#if (legacy) 
    LegacySystemEmployee.Save(Employee e) 
#endif
}

In order for the conitional code to be active you must define the legacy identifier either using

#define legacy

or as a conditional compilation symbol during the complilation.

Obalix