解析来自4种不同API的响应的正确OOP方法是什么?

时间:2013-12-26 17:40:35

标签: python oop

什么是正确的代码方法,例如,Weather类,它解析4个不同的来源?这是我如何做到的:

创建了一个名为Weather的类,其中包含4个属性(例如tempwindspeedpressurehumidity)和4个方法,例如{{1 },...,parse_source1。为了获得结果,我创建了4个对象,并在每个对象上调用不同的方法。

但是现在我很困惑,如果这是解决这个问题的正确方法。也许我应该创建具有所有属性的parse_source4类,然后使用继承并将解析放入Weather

3 个答案:

答案 0 :(得分:2)

我不确定这是一个适当的问题,因为可能有太多“正确”的方法,但无论如何,这是一个我发现太多次的问题,同样的解决方案总是起作用我,用各种语言。

我会说每个对象都有一个解析器类会更好:

class JSONWeatherParser(object):
    def parse(self, value):
        json_obj =  json.load(value)
        w = Weather()
        # Do some stuff here, assign values from json_obj to w etc.
        return w

class XMLWeatherParser(object):
    def parse(self, value):
        element = xml.etree.ElementTree(value)
        w = Weather()
        # Do some stuff here, assign values from element to w etc.
        return w

class YAMLWeatherParser(object):
    def parse(self, value):
        w = Weather()
        # Sorry, I do not even know what it looks like
        return w

将课程放在字典上也很酷:

weather_parsers = {
    'xml': XMLWeatherParser,
    'json': JSONWeatherParser,
    'yaml': YAMLWeatherParser
}

现在你可以做到:

format = request.get('format') # For example
data = request.get('weather')
parser = weather_parsers[format]()
weather = parser.parse(data)

事实上,在Python中你甚至不需要这些*WeatherParser类:你可以创建*_weather_parser 函数,这会更简单:

def json_weather_parse(value):
    json_obj =  json.load(value)
    w = Weather()
    # Do some stuff here, assign values from json_obj to w etc.
    return w

def xml_weather_parse(value):
    element = xml.etree.ElementTree(value)
    w = Weather()
    # Do some stuff here, assign values from element to w etc.
    return w

def yaml_weather_parse(value):
    w = Weather()
    # Sorry, I do not even know what it looks like
    return w

如果你的解析器只做的解析器并不保留状态,那么函数是一个更好的选择。 OTOH的类方法更通用,语言无关且功能强大。关键是,你可能不需要那么大的力量。

总结:虽然从理论上讲,为每种行为制作不同的Weather课程会很酷(所有孩子都在这样做! - 或者他们在90年代都是这样做的)实践中,将解析问题与模型分开似乎更易于管理。

编辑:HannesOvrén提出了一个很好的问题。

实际上,解析器类更复杂,我宁愿使用解析器函数。现在,为什么不制作Weather方法呢?好吧,解析一些特定的类'实例并不像这个类所期望的行为那样,所以看起来更好的范围是将这个问题放在不同的地方。当然,我们不会指望一个不存在的实例来解析它自己!

当然,我们可以将它放在类方法上,就像在Django等人中完成的那样,但为什么要创建一个方法,如果一个函数会这样做?在这种情况下,它与风格更相关,我在these old school rules;)

播放

更重要的是,这在某种意义上是一种风格问题,我的方法将是所描述的。但是,我知道这只是一种方法,还有许多其他方法与此方法一样有用且“正确”。我不认为类方法是错误的,但我也不会使用它们。

答案 1 :(得分:1)

最好将Weather类与解析代码分开,即

class Weather:
    def __init__(...):
        ...

def parse_weather(source):
    if source == ...:
        ...
    return Weather(...)

这样,添加或删除源时,您的类不必更改。你甚至可以创建一个单独的类;

class WeatherParser:
    def __init__(source):
        ...
    def parse_weather(...):
        ...
        return Weather(...)

哪个包含你的解析方法

答案 2 :(得分:1)

如果您是该类的唯一实现者,我将使用@classmethod装饰器来创建工厂函数。这样,解析器/源很容易找到,因为它们是Weather类的一部分。

class Weather(object):
    def __init__(self, temp, windspeed, humidity, pressure):
        # Initialize everything ...

    @classmethod
    def from_source1(cls, source1):
        # Parse source 1, get temp, windspeed, humidity and pressure
        # ...
        instance = cls(temp, windspeed, humidity, pressure)
        return instance


weather = Weather.from_source1(source1)

如果您希望其他人使用您的课程,并且可能想要实施他们自己的资源,那么我认为您有两个不错的选择:

  1. __init__中进行解析并让用户对您的Weather基类进行子类化。

  2. 创建一个WeatherParser基类,让用户继承该基类。

  3. 我认为第一个选项更直观,因为您避免创建更多类。 最重要的是(在我看来),对于添加新资源的正确方法毫无疑问。