Factory method of a python class returning implementation based on system and design issues
Question: # 1) Introduction

I have started the implementation of a tool in Python that gathers several
system metrics (e.g. cpu utilisation, cpu saturation, memory errors etc.) and
presents them to the end-user. This tool should ideally support as many
platforms as possible (Linux, FreeBSD, Windows etc.).

I have completed the implementation of this tool for a Linux system for a few
metrics I consider important and I have just started to implement the same
metrics for a FreeBSD system. This tool must be designed in a way that allows
support for more **system metrics** and for more **platforms** in the future.
Moreover, a **web-interface** will soon be added and will **receive data**
from my tool.

# 2) My design decisions so far

For the above reasons, I have decided to implement the tool in **Python**
(convenient to read data from different sources on many systems and ,well, I
am somewhat more familiar with it :)) and I am following a **class structure**
for each system metric (inheritance is important as some systems share
features so there is no need to rewrite code). Moreover, I have decided that I
have a valid use case for using a **factory method**.

## 2.1) Class structure

Here is an example class diagram for CPU Metrics (simplified for the sake of
the question):

    
    
                      CpuMetrics        (Abstract Base Class)
                     /      |    \
                    /       |     \
                   /        |      \
                  /         |       \
                 /          |        \
                /           |         \
    LinuxCpuMetrics  FreeBSDCpuMetrics WindowsCPUMetrics   (per OS)
               /  \ 
              /    \
             /      \
            /        \
           /          \
          /            \
         /              \
    ArchLinuxCpuMetrics  DebianLinuxCpuMetrics             (sometimes important per Distro or Version)
    

## 2.2) Factory Method

In the Abstract Base Class called **CpuMetrics** there are some abstract
methods defined that should be implemented by inheriting classes and a
**factory method** called get_impl(). I have done some research on when I
should use a Factory Method (for example, answers such as
[this](http://stackoverflow.com/a/14992545/2568511)) and I believe it is valid
to use one in my case.

For example, I want a client (e.g. my web interface) to call my tool to get
CPU Utilisation metrics like this:

    
    
    cpu_metrics = CpuMetrics.get_impl() # factory method as an alternative constructor
    cpu_metrics.get_cpu_util() # It is completely transparent for the client which get_cpu_util() is returned.
    

# 3) My concern and my question (finally)

Following the above analyzed design, it is very important for my factory
method to be informed about which system are we on now ("is this Linux,
Windows? Which implementation should I bring now?"). Therefore, I have to
**heavily rely** on functions such as `platform.system()` or its alternatives.
So what my factory method does is (roughly again):

    
    
    def get_impl():
        """Factory method returning the appropriate implementation depending on system."""
        try:
            system = platform.system() # This returns: { Linux, Windows, FreeBSD, ... }
            system_class = getattr("cpu", system + "CpuMetrics" )
        except AttributeError, attr_err:
            print ("Error: No class named " + system + "CpuMetrics in module cpu. ")
            raise attr_err
        return system_class()
    

I feel **very uncomfortable** with this for two reasons:

1) I force a future programmer (or even myself) to follow a naming convention
for his class. For example, if someone decides to extend my system, say, for
Solaris he **absolutely has to** name his class `SolarisCpuMetrics`.

2) If in a future version of Python the values of `platform.system()` (or an
other alternative I will choose to use) are modifiled, then I have to change
my naming convention and modify my factory method a lot.

So my **question** : is there a workaround for my concern ? Will my code
become unreadable or my concern is not valid? If you believe there is one
workaround, how much do I need to modify / refactor my code and change my
design?

I don not have experience in designing projects from scratch, so I could use
any advice. Also, I have some more experience in Java. I try to think in a as
much pythonic way as possible when writing Python, but sometimes fail to do a
proper seperation between the two. Your constructive criticism is very
desirable.


Answer: Use a class decorator to enumerate classes. And override the
[allocator](http://docs.python.org/3/reference/datamodel.html#object.__new__).

    
    
    sysmap = {}
    
    class metric:
      def __init__(self, system):
        self.system = system
      def __call__(self, cls):
        sysmap[self.system] = cls
        return cls
    
    class CpuMetrics:
      def __new__(self):
        cls = sysmap.get(platform.system)
        if not cls:
          raise RuntimeError('No metric class found!')
        else:
          return cls()
       ...
    

...

    
    
    @metric('Linux')
    class SomeLinuxMetrics(CpuMetrics):
       ...
    

...

    
    
    metrics = CpuMetrics()
    

