Strategy Design Pattern

A different strategy but same interface.

Brief Overview of The Strategy Pattern

The Strategy or Policy Pattern is one of the behavioral design patterns from the gang of four design patterns book. It is primarily used when the specific implementation or algorithm cannot be determined until runtime.

When To Implement

There are several common software design problems that are easily solved by implementing the strategy pattern:

  • There are a number of classes that have the same attributes but vary in a specific method implementation. By implementing the strategy pattern a single method call can now have many behaviors.
  • There is one action that can be implemented in various ways.  The strategy pattern will allow for the correct implementation to be chosen at runtime.
  • There is a class that has many different behaviors that are being determined by multiple if statements. The strategy pattern helps here by moving the related conditional branches into their own classes.

Strategy Pattern Components

The strategy pattern is typically comprised of three components and a client. The first component is the context which is used to return the correct concrete strategy at runtime.  The second component is a class that acts as the base strategy which is typically a parent class that has the strategy method implemented as an abstract method (the whole class is abstract). The third component is the concrete strategies which inherit from the parent strategy class and have specific implementations of the abstract method.  The client will have a context and the context will have a reference to the strategy object and using polymorphism will be configured with the correct concrete strategy at runtime.

Implementation of the Strategy Pattern

This implementation uses the basic structure of the design pattern.

The Context

The context is essentially used to determine which concrete strategy is needed by passing in some condition, for this example the temperature to convert from, and then instantiating it and allowing the client to interact with it using the sub class’s concrete implementation of the abstract method.


class TempConvertInterfaceContext

   #the initialize methods figures out the concrete strategy and then assigns it
   #to the convert strategy instance variable.  Typically this would be an if
   #statement in some implementations but ruby allows us to do a little meta
   #programming.

   def initialize(convert_from)
     @convert_strategy =
     Object.const_get("#{convert_from.capitalize}Strategy").new
   end

   def convert_temperature(convert_to, temperature)
     @convert_strategy.convert_temperature(convert_to, temperature)
   end

end

Abstract Interface For Concrete Strategies

All concrete instances of the strategy should inherit from this class and implement the abstract method so the context and client do not have to care about the implementation. The point of the interface is to define a method that must be implemented in all sub classes.


class StrategyInterface

  #In ruby we really don't need this interface at all.  Ruby will throw
  #a NoMethod error if a method doesn't exist which is essentially what
  #I am doing here. For sake of sticking to the GOF implementation I will
  #use this class and method as an interface.
  def convert_temperature(convert_to, temperature)
    raise "Must implement this method."
  end

end

Concrete Implementations of Strategy Interface

Each of these classes inherits from the StrategyInterface class and implements the abstract convert_temperature method.

class KelvinStrategy < StrategyInterface

  def convert_temperature(convert_to, temperature)
    case convert_to
    when 'celsius'
      temperature - 273.15
    when 'fahrenheit'
      temperature * 9.0 / 5.0 - 459.67
    when 'kelvin'
      temperature
    else
      raise "This Scale is currently not supported"
    end
  end

end
class FahrenheitStrategy < StrategyInterface

  def convert_temperature(convert_to, temperature)
    base_calculation = (temperature - 32) * 5.0 / 9.0
    case convert_to
    when 'celsius'
      base_calculation
    when 'kelvin'
       base_calculation + 273.15
    when 'fahrenheit'
       temperature
    else
       raise "This Scale is currently not supported"
    end
  end
end
class CelsiusStrategy < StrategyInterface

  def convert_temperature(convert_to, temperature)
    case convert_to
    when 'fahrenheit'
      temperature * 9.0 /5.0 + 32
    when 'kelvin'
      temperature + 273.15
    when 'celsius'
      temperature
    else
      raise "This Scale is currently not supported"
    end
  end

end

The Client

The client is essentially the driving mechanism that needs to use the strategy but doesn’t know which of the strategies it will need until runtime.


class Client
  # The client has a context which is used to determine the
  # specific concrete strategy and then return that strategy back to the client.
  # The values in this array are different concrete strategies that
  # will be chosen at runtime to implement.
  ['fahrenheit_to_celsius', 'fahrenheit_to_kelvin', 'celsius_to_fahrenheit',
  'celsius_to_kelvin', 'kelvin_to_celsius', 'kelvin_to_fahrenheit'].each do | temperature_scale_conversion_direction |
      #Parsing the string into the two temperature scales.
      convert_from, convert_to = temperature_scale_conversion_direction.split(/_to_/)
      #This instantiates the context with the
      #specific concrete strategy and returns the concrete strategy.
      temp_converter = TempConvertInterfaceContext.new(convert_from)
      #Printing the converted temperature.
      puts temp_converter.convert_temperature(convert_to, 0)
    end
end

Get the Code

Here is the Github repository for the code. You will notice I also made another version more idiomatic to ruby using Procs.

Final Thoughts

The Strategy Pattern is extremely handy to use when you need to check the type of something and then perform an action on it. If the type is not known until runtime, using the context to return the correct strategy removes the burden from the client, who in all honesty should not care about the implementation at all.

Ruby Gem

I created a ruby gem from this post it can be found here.  The source code for the gem can be located here.

Singleton: One is the Loneliest Number

Being single can be fun just ask the singleton.

What is a Singleton?

A singleton is a creational design pattern in which a class is responsible for the creation and management of its sole instance and it provides a way for the instance to be accessed from the global namespace.

For more information on the singleton pattern I highly recommend Source Making’s explanation.

The Singleton and Me

Currently I use a custom logging mechanism that is implemented using the singleton pattern and a more basic version of this will be what I use in the code example. The logger needs to behave differently based on the environment in which it is executed (development, testing, or production). Loggers in general are typically designed as a singleton.  Subclassing a singleton is not different logistically as it would be with any other class. The trick is to make sure that proper instance is available when requested.  For this purpose I used a registry of singletons.

Let’s Get to the Code

The code below is written in ruby and is one of the many ways to create a singleton along with its registry in this language.  It is composed of the Logger class and two of its children, the ProductionLogger and the DevelopmentLogger.

The Logger Class

class Logger

  @@instance = new

  def initialize *args, &block
    populate_registry
  end

  def self.instance
    Logger.singleton_registry_look_up ENV['DEVELOPMENT_ENVIRONMENT']
  end

  #using a mutex for thread safety
  def self.mutex
    @mutex ||= Mutex.new
  end

  def self.registry
    @registry ||= {}
  end

  #force all children to implement log so there is a common interface
  def log information
    raise "Must Implement Log Method"
  end

  def close
    @log.nil? ? (raise "Must Declare Log Variable as @log") : @log.close
  end

  def self.singleton_registry_look_up singleton_name
    self.registry[singleton_name.to_sym]
  end

  private

  def register singleton_name, logger_type
    self.class.registry[singleton_name.to_sym] = logger_type
  end 

  #major drawback of using static variables is that all subclasses have to be
  #instantiated so that they can be registered
  def populate_registry
    ["DevelopmentLogger", "ProductionLogger"].each do |logger_type|
       register logger_type, Object.const_get(logger_type).send(:new)
    end
  end

  def logger_mutex
    self.class.mutex.synchronize { yield }
  end

  private_class_method :new
end
What Makes Logger Class a Singleton

Making the Logger.new method private keeps new Logger instances from being created, the only Logger instance belongs in the @@instance class variable.

Setting Up the Registry of Singletons

When the new method is called and assigned to the @@instance variable it performs new’s normal duties which involves calling the private method initialize . The initialize method on the Logger class starts a chain of events that create the registry and then populates it.

The registry itself, a hash, holds the name of the classes (keys) and also an instance of the class (values). The point of the registry of singletons is to provide the correct instance when an instance is requested. This is done via the Logger.singleton_registry_look_up which takes the string name of the class and returns an instance. I prefer to read the string from the environment but there are other ways to do this as well.

The DevelopmentLogger Class

class DevelopmentLogger < Logger

  def initialize *args, &block
    @log = File.open('log/development.log', 'a')
  end

  def log information
    #development log does not need to redact any information
    logger_mutex { @log.puts information }
  end

end

This class inherits from the Logger class and overwrites the initialize method to assign the proper log file to the class variable called @log . It also implements the log method which is abstracted in the parent.  The log method literally just appends the argument to the file assigned to the @log variable.

The ProductionLogger Class

class ProductionLogger < Logger

  def initialize *args, &block
    @log = File.open('log/production.log', 'a')
  end

  def log information
    #the actual password should be redacted in production log
    logger_mutex { @log.puts information.gsub(/(?<=password:\s).*/im, "FILTERED") }
  end
end

This class also overwrites the initialize method and opens the correct log for production.  The ProductionLogger’s log implementation filters out any potential passwords that meet the regular expression from the log file.

Using the Logger Class

#inject into the application
load './logger.rb'

#access the instance
LOGGER = Logger.instance

#write to log
LOGGER.log "Hello Log!"

Using load to inject the Logger into your application executes the @@instance assignment.  Assigning the Logger.instance to a constant ensure reassignment won’t happen later.

The Singleton and Its Registry

There are plenty of reasons people do not use the singleton design pattern. Furthermore using a registry can cause further implementation problems. One implementation choice I struggled with was when and how to register subclasses in the registry. I came to the conclusion that it varies on language and needs. Even though the singleton does have drawbacks in my opinion there are valid use cases for them. For instance a logger being implemented as a singleton alleviates the probability of several different objects trying to access the same resource (usually a file) at the same time. If you throw in some thread safety you can be confident the log file has optimal integrity.

Find the Code

Singleton With Registry Repo

* For the sake of this tutorial I did not use ruby’s multiton or singleton modules, however the same effect could have been achieved with them.