python类的工厂方法基于系统和设计问题返回实现

Factory method of a python class returning implementation based on system and design issues

1)导言

我已经开始在python中实现一个工具,它收集了几个系统指标(例如CPU利用率、CPU饱和、内存错误等),并将它们呈现给最终用户。这个工具应该理想地支持尽可能多的平台(Linux、FreeBSD、Windows等)。

我已经为Linux系统完成了这个工具的实现,其中有一些我认为很重要的指标,我刚刚开始为FreeBSD系统实现相同的指标。该工具的设计必须能够支持更多的系统度量和未来更多的平台。此外,很快将添加一个Web界面,并从我的工具接收数据。

2)我目前的设计决策

出于上述原因,我决定在python中实现该工具(方便在许多系统上从不同的源读取数据,而且我对它比较熟悉:),并且我对每个系统度量都遵循一个类结构(继承很重要,因为一些系统共享特性,所以不需要重写代码)。此外,我已经决定使用工厂方法有一个有效的用例。

2.1)阶级结构

下面是一个CPU度量的类图示例(为了这个问题简化了):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
                  CpuMetrics        (Abstract Base Class)
                 /      |    \
                /       |     \
               /        |      \
              /         |       \
             /          |        \
            /           |         \
LinuxCpuMetrics  FreeBSDCpuMetrics WindowsCPUMetrics   (per OS)
           /  \
          /    \
         /      \
        /        \
       /          \
      /            \
     /              \
ArchLinuxCpuMetrics  DebianLinuxCpuMetrics             (sometimes important per Distro or Version)

2.2)工厂法

在名为cpummetrics的抽象基类中,定义了一些抽象方法,这些方法应通过继承类和名为get_impl()的工厂方法来实现。我做了一些关于何时应该使用工厂方法的研究(例如,这样的答案),我相信在我的案例中使用工厂方法是有效的。

例如,我希望一个客户机(例如我的Web界面)调用我的工具来获取CPU利用率指标,如下所示:

1
2
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)我的关心和我的问题(最后)

根据以上分析的设计,我的工厂方法非常重要,可以了解我们现在使用的是哪个系统("这是Linux,Windows吗?"我现在应该带来哪种实现呢?")因此,我不得不严重依赖诸如platform.system()或其替代功能。所以我的工厂方法做的是(粗略地说一次):

1
2
3
4
5
6
7
8
9
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()

我对此感到非常不舒服,有两个原因:

1)我强迫未来的程序员(甚至我自己)遵循他的类的命名约定。例如,如果有人决定扩展我的系统,比如说,对于Solaris,他必须将类命名为SolarisCpuMetrics

2)如果在未来的python版本中修改了platform.system()的值(或者我选择使用的其他选项),那么我必须更改我的命名约定并修改很多工厂方法。

所以我的问题是:我是否有解决办法?我的代码会变得不可读还是我的问题无效?如果您认为有一个解决方法,我需要修改/重构代码和更改设计多少?

我没有从零开始设计项目的经验,所以我可以使用任何建议。另外,我在Java方面有更多的经验。在编写Python时,我尽量用Python式的方式进行思考,但有时无法在两者之间进行适当的分离。你的建设性批评是非常可取的。


使用类修饰器枚举类。并重写分配器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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()
   ...

1
2
3
@metric('Linux')
class SomeLinuxMetrics(CpuMetrics):
   ...

1
metrics = CpuMetrics()