Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strategy pattern in Python when a "strategy" consists of more than one function

Tags:

python

I understand that because Python has first-class functions, using the Strategy pattern is usually just a matter of passing a function as an argument, and doesn't require futzing with classes. But what if the "strategies" aren't single functions, but rather groups of related functions that logically should be selected as a set?

Like, here's a trivial and contrived example:

class HexFormatter(object):
  """Base class for strategies to format hexadecimal numbers."""
  pass

class Motorola(HexFormatter):
  """Format Motorola style (e.g. $1234)"""
  @staticmethod
  def formatbyte(n):
    return "$%02X" % n

  @staticmethod
  def formatword(n):
    return "$%04X" % n

class Intel(HexFormatter):
  """Format Intel-style (e.g. 1234h)"""
  @staticmethod
  def formatbyte(n):
    return "%02Xh" % n

  @staticmethod
  def formatword(n):
    return "%04Xh" % n

The idea is you pick a strategy and you get the function for formatting bytes and the function for formatting words as a set, rather than needing to specify them individually. This example is akin to how you'd do it in a language like C++ (except the methods wouldn't be static because you can't have virtual static methods in C++) and it's not as if it doesn't work in Python. But it involves defining a bunch of "classes" that only have static methods and aren't meant to be instantiated, which seems un-Pythonic somehow.

Is there a more idiomatic way to do this in Python?

like image 754
Alex Jackson Avatar asked May 18 '16 17:05

Alex Jackson


People also ask

What is strategy pattern in Python?

Strategy pattern follows the Open/close principle; a software application is open for extension but closed for modification. It means you can add any number of additional strategies without modifying the main class. It makes your code more flexible and easy to maintain.

What type of design pattern is strategy?

Strategy is a behavioral design pattern that lets you define a family of algorithms, put each of them into a separate class, and make their objects interchangeable.

How do you use strategy patterns?

Use the Strategy pattern when you want to use different variants of an algorithm within an object and be able to switch from one algorithm to another during runtime. Use the Strategy when you have a lot of similar classes that only differ in the way they execute some behavior.

What is strategy pattern in Java?

Strategy design pattern is one of the behavioral design pattern. Strategy pattern is used when we have multiple algorithm for a specific task and client decides the actual implementation to be used at runtime.


1 Answers

One option I've found quite nice when you have many functions in each strategy, although perhaps a bit too much for something as small as this, is to define each strategy in a separate module

motorola.py

def formatbyte(n):
    return "$%02X" % n

def formatword(n):
    return "$%04X" % n

intel.py

def formatbyte(n):
  return "%02Xh" % n

def formatword(n):
  return "%04Xh" % n

Then as modules are first-class objects in Python as you pointed out, you can simply pass them when using your strategy.


The other alternative is to just consider passing each element of a strategy as a plain function parameter to whatever they are being used for in client code based on your context. For instance instead of having

def some_func(obj):
    obj.format_byte(...)
    # other stuff
    obj.format_word(...)

You could have

def some_func(format_byte, format_word):
    format_byte(...)
    #
    format_word(...)

In any case it doesn't make sense to go the OOP route if you have no more than static methods for each strategy - no two instances of any type will be any different as there is no instance data.

like image 177
miradulo Avatar answered Sep 21 '22 10:09

miradulo