Wednesday, April 23, 2008

Strategy Pattern

The pattern states: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. Look at the below example demonstrating a potential problem:

Class: Logger
1
2
3
4
5
6
7
8
9
10
namespace Strategy
{
    public class Logger
    {
        public void Log(string logMessage)
        {
            Console.WriteLine(logMessage);
        }
    }
}
You see that this is a really simple logging class logging messages to the console, but now we also want to be able to log to a file. Well you could add a new method to log to a file, but that would mean that all the classes using this Logger class has to change using the new method. So that is a no go. Take a look at the below example using the Strategy Pattern to make this possible without the need to change the client code:
Interface: ILogHandler
1
2
3
4
5
6
7
namespace Strategy
{
    public interface ILogHandler
    {
        void Log(string logMessage);
    }
}
Class: Logger
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace Strategy
{
    public class Logger
    {
        private ILogHandler _LogHandler;

        public void SetLogHandler(ILogHandler logHandler)
        {
            _LogHandler = logHandler;
        }

        public void Log(string logMessage)
        {
            if (_LogHandler != null)
            {
                _LogHandler.Log(logMessage);
            }
        }
    }
}
When we implement the Logger class in this way than it is according to the Open Closed Principle. We could provide any implementation of the ILogHandler without the need to make any modifications to the class. For example:
Class: ConsoleLogger : ILogHandler
1
2
3
4
5
6
7
8
9
10
namespace Strategy
{
    public class ConsoleLogger : ILogHandler
    {
        public void Log(string logMessage)
        {
            Console.WriteLine(logMessage);
        }
    }
}
Class: FileLogger : ILogHandler
1
2
3
4
5
6
7
8
9
10
namespace Strategy
{
    public class FileLogger : ILogHandler
    {
        public void Log(string logMessage)
        {
            // Log to file functionality
        }
    }
}
I hope you found these examples helpful. Also take a look at the following links:

http://www.dofactory.com/Patterns/PatternStrategy.aspx
http://patnys.com/archive/2008/04/15/strategy-pattern.aspx

No comments: