niedziela, 12 maja 2013

Design patterns: (Abstract) Factory in Python: some theory

First design pattern by GoF I'll try to implement in Python is Abstract Factory. To read an introduction to design patterns and Gang of Four (GoF) see my previous post.

(Abstract) Factory: some theory

What is it?

A factory, as you can guess by its name, is supposed to produce lots of similar products - and by
products we mean classes. GoF describes this method as good for creating families of related or dependant objects.

Structure


Objects, objects everywhere!

GoF introduces structures like AbstractFactory and ConcreteFactory. AbstractFactory is just an abstract class, which defines some methods for concrete implementations (ConcreteFactory1, ConcreteFactory2, etc.). AbstractFactory should have methods for creating object, e.g. make_object should return instantiated AbstractObject. ConcreteFactory1 and ConcreteFactory2 would return SomeObject1 and SomeObject2, which are AbstractObject's implementation. Such AbstractFactory was introduced so that its implementations could be interchangeable. Let's see how this would look translated directly to Python:
# too much code!
import abc

class AbstractFactory(object):

    __metaclass__ = abc.ABCMeta
    
    @abc.abstractmethod
    def make_object(self):
        return

class ConcreteFactory1(AbstractFactory):
    def make_object(self):
        # do something
        return SomeObject1()

class ConcreteFactory2(AbstractFactory):
    def make_object(self):
        # do something else
        return SomeObject2()

I used the Python's built-in abc module, which allows to define Abstract Base Classes (ABC).
But in Python we don't need a common base class to pass different classes to a function - Python is dynamically typed, you can pass anything everywhere. Here's a more Pythonic approach, which is definitely less verbose:
# better example
class ConcreteFactory1(object):
    def make_object(self):
        # do something
        return SomeObject1()

class ConcreteFactory2(object):
    def make_object(self):
        # do something else
        return SomeObject2()

So actually, in this Abstract Factory example there's no explicit abstract factory class, hence I've put parentheses in  the title.
Abstract Factory is somewhat implicit now

Usage

So now we know how a basic factory looks like, but what can we use it for? The short answer is: when in need of common interface or when you have to do sequences of operations with objects that are created differently. Usage of this abstract factory could look like this
def client_function(factory):
    an_object = factory.make_object()

    # do something with an_object...

    return a_result

def prepare_client():
    factory1 = ConcreteFactory1()
    result1 = client_function(factory1)
    factory2 = ConcreteFactory2()
    result2 = client_function(factory2)
Some real-life examples could be:

  • according to GoF: providing different look-and-feel for operating systems (e.g different looking buttons, scrollbars, etc.)
  • one I can think of: creating similar objects from multiple data sources (e.g. database, XML, JSON, user input etc.)
  • ...? (Any ideas? Share!)

Coming soon: full Python example

I've prepared an example in Python from the GoF book. I want to keep my blog posts concise, so I'll put it in a different post. It'll be a very simple text game. There'll be wizards and magic!

Brak komentarzy:

Prześlij komentarz