美文网首页
python设计模式-1工厂设计模式-2工厂方法

python设计模式-1工厂设计模式-2工厂方法

作者: python测试开发 | 来源:发表于2021-04-02 05:14 被阅读0次

    工厂方法简介

    工厂方法是为处理对象创建任务而编写的函数,使用工厂方法时,我们不需要知道创建对象是如何实现的。

    Django网络框架使用工厂方法模式来创建网络表单的字段。Django中包含的表单模块,支持创建不同种类的字段(例如CharField、EmailField等)。而且它们的部分行为可以通过max_length或required等属性进行自定义。

    from django import forms
    class PersonForm(forms.Form):
    name = forms.CharField(max_length=100)
    birth_date = forms.DateField(required=False)
    

    实现工厂方法: json和xml解析

    • 需求

    在这个案例中,我们有一些输入数据存储在XML和JSON文件中,我们想解析它们并检索信息。同时我们希望同意客户端与这些(以及未来所有)外部服务的连接。我们将使用工厂方法来解决这个问题。这个例子只关注XML和JSON,但增加对更多服务的支持也是类似的。

    首先,我们来看看数据文件。

    JSON文件movies.json是一个包含美国电影信息(片名、年份、导演姓名、类型等)数据集的例子(在GitHub上找到)。这实际上是一个很大的文件,但这里是一个摘录,为了更好的可读性而进行了简化,以显示其内容是如何组织的。

    [
    {"title":"After Dark in Central Park",
    "year":1900,
    "director":null, "cast":null, "genre":null},
    {"title":"Boarding School Girls' Pajama Parade",
    "year":1900,
    "director":null, "cast":null, "genre":null},
    {"title":"Buffalo Bill's Wild West Parad",
    "year":1900,
    "director":null, "cast":null, "genre":null},
    {"title":"Caught",
    "year":1900,
    "director":null, "cast":null, "genre":null},
    {"title":"Clowns Spinning Hats",
    "year":1900,
    "director":null, "cast":null, "genre":null},
    {"title":"Capture of Boer Battery by British",
    "year":1900,
    "director":"James H. White", "cast":null, "genre":"Short documentary"},
    {"title":"The Enchanted Drawing",
    "year":1900,
    "director":"J. Stuart Blackton", "cast":null,"genre":null},
    {"title":"Family Troubles",
    "year":1900,
    "director":null, "cast":null, "genre":null},
    {"title":"Feeding Sea Lions",
    "year":1900,
    "director":null, "cast":"Paul Boyton", "genre":null}
    ]
    

    XML文件person.xml是基于维基百科的例子(j.mp/wikijson),包含了个人的信息(名,姓,性别等),如下所示。

    <persons> 
      <person> 
        <firstName>John</firstName> 
        <lastName>Smith</lastName> 
        <age>25</age> 
        <address> 
          <streetAddress>21 2nd Street</streetAddress> 
          <city>New York</city> 
          <state>NY</state> 
          <postalCode>10021</postalCode> 
        </address> 
        <phoneNumbers> 
          <phoneNumber type="home">212 555-1234</phoneNumber> 
          <phoneNumber type="fax">646 555-4567</phoneNumber> 
        </phoneNumbers> 
        <gender> 
          <type>male</type> 
        </gender> 
      </person> 
      <person> 
        <firstName>Jimy</firstName> 
        <lastName>Liar</lastName> 
        <age>19</age> 
        <address> 
          <streetAddress>18 2nd Street</streetAddress> 
          <city>New York</city> 
          <state>NY</state> 
          <postalCode>10021</postalCode> 
        </address> 
        <phoneNumbers> 
          <phoneNumber type="home">212 555-1234</phoneNumber> 
        </phoneNumbers> 
        <gender> 
          <type>male</type> 
        </gender> 
      </person> 
      <person> 
        <firstName>Patty</firstName> 
        <lastName>Liar</lastName> 
        <age>20</age> 
        <address> 
          <streetAddress>18 2nd Street</streetAddress> 
          <city>New York</city> 
          <state>NY</state> 
          <postalCode>10021</postalCode> 
        </address> 
        <phoneNumbers> 
          <phoneNumber type="home">212 555-1234</phoneNumber> 
          <phoneNumber type="mobile">001 452-8819</phoneNumber> 
        </phoneNumbers> 
        <gender> 
          <type>female</type> 
        </gender> 
      </person> 
    </persons> 
    
    • 实现
    import json
    import xml.etree.ElementTree as etree
    
    
    class JSONDataExtractor:
    
        def __init__(self, filepath):
            self.data = dict()
            with open(filepath, mode='r', encoding='utf-8') as f:
                self.data = json.load(f)
    
        @property
        def parsed_data(self):
            return self.data
    
    
    class XMLDataExtractor:
    
        def __init__(self, filepath):
            self.tree =  etree.parse(filepath)
    
        @property
        def parsed_data(self):
            return self.tree
    
    
    def dataextraction_factory(filepath):
        if filepath.endswith('json'):
            extractor = JSONDataExtractor
        elif filepath.endswith('xml'):
            extractor = XMLDataExtractor
        else:
            raise ValueError('Cannot extract data from {}'.format(filepath))
        return extractor(filepath)
    
    
    def extract_data_from(filepath):
        factory_obj = None
        try:
            factory_obj = dataextraction_factory(filepath)
        except ValueError as e:
            print(e)
        return factory_obj
    
    
    def main():
        sqlite_factory = extract_data_from('data/person.sq3')
        print()
    
        json_factory = extract_data_from('data/movies.json')
        json_data = json_factory.parsed_data
        print(f'Found: {len(json_data)} movies')
        for movie in json_data:
            print(f"Title: {movie['title']}")
            year = movie['year']
            if year:
                print(f"Year: {year}")
            director = movie['director']
            if director:
                print(f"Director: {director}")
            genre = movie['genre']
            if genre:
                print(f"Genre: {genre}")
            print()
    
        xml_factory = extract_data_from('data/person.xml')
        xml_data = xml_factory.parsed_data
        liars = xml_data.findall(f".//person[lastName='Liar']")
        print(f'found: {len(liars)} persons')
        for liar in liars:
            firstname = liar.find('firstName').text
            print(f'first name: {firstname}')
            lastname = liar.find('lastName').text
            print(f'last name: {lastname}')
            [print(f"phone number ({p.attrib['type']}):", p.text) 
                  for p in liar.find('phoneNumbers')]
            print()
        print()
    
    
    if __name__ == '__main__':
        main()
    

    虽然 JSONDataExtractor 和 XMLDataExtractor 有相同的接口,但 parsed_data() 返回的内容并不是以统一的方式处理的。必须使用不同的 Python 代码来处理每个数据提取器。尽管能够为所有的提取器使用相同的代码会很好,但这在大多数情况下是不现实的,除非我们为数据使用某种通用的映射,这通常是由外部数据提供者提供的。

    相关文章

      网友评论

          本文标题:python设计模式-1工厂设计模式-2工厂方法

          本文链接:https://www.haomeiwen.com/subject/sritkltx.html