Pyhotn工厂模式

工厂模式形式

  • 工厂方法:对不同的输入参数返回不同对象;
  • 抽象工厂:是一组用于创建一系列相关事物对象的工厂方法。

工厂方法

数据来源形式:

  • 人们可读文件:XML、Atom、YAML、JSON等
  • 二进制文件:.sq3、.mp3

问题:

  • 有一些数据存储在XML和JSON文件中,对这两个文件进行解析,获取一些信息;
  • 对这些外部服务进行集中式的客户端连接。

数据形式:

  • JSON
[
    {
        "id": "0001",
        "type": "donut",
        "name": "Cake",
        "ppu": 0.55,
        "batters": {
            "batter": [
                {
                    "id": "1001",
                    "type": "Regular"
                },
                {
                    "id": "1002",
                    "type": "Chocolate"
                },
                {
                    "id": "1003",
                    "type": "Blueberry"
                },
                {
                    "id": "1004",
                    "type": "Devil's Food"
                }
            ]
        },
        "topping": [
            {
                "id": "5001",
                "type": "None"
            },
            {
                "id": "5002",
                "type": "Glazed"
            },
            {
                "id": "5005",
                "type": "Sugar"
            },
            {
                "id": "5007",
                "type": "Powdered Sugar"
            },
            {
                "id": "5006",
                "type": "Chocolate with Sprinkles"
            },
            {
                "id": "5003",
                "type": "Chocolate"
            },
            {
                "id": "5004",
                "type": "Maple"
            }
        ]
    },
    {
        "id": "0002",
        "type": "donut",
        "name": "Raised",
        "ppu": 0.55,
        "batters": {
            "batter": [
                {
                    "id": "1001",
                    "type": "Regular"
                }
            ]
        },
        "topping": [
            {
                "id": "5001",
                "type": "None"
            },
            {
                "id": "5002",
                "type": "Glazed"
            },
            {
                "id": "5005",
                "type": "Sugar"
            },
            {
                "id": "5003",
                "type": "Chocolate"
            },
            {
                "id": "5004",
                "type": "Maple"
            }
        ]
    },
    {
        "id": "0003",
        "type": "donut",
        "name": "Old Fashioned",
        "ppu": 0.55,
        "batters": {
            "batter": [
                {
                    "id": "1001",
                    "type": "Regular"
                },
                {
                    "id": "1002",
                    "type": "Chocolate"
                }
            ]
        },
        "topping": [
            {
                "id": "5001",
                "type": "None"
            },
            {
                "id": "5002",
                "type": "Glazed"
            },
            {
                "id": "5003",
                "type": "Chocolate"
            },
            {
                "id": "5004",
                "type": "Maple"
            }
        ]
    }
]
  • XML
<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 xml.etree.ElementTree as etree#导入python自带库,用来处理XML
import json#处理JSON


class JSONConnector:#类JSONConnector解析JSON文件

    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 XMLConnector:#类XMLConnector解析XML文件

    def __init__(self, filepath):
        self.tree = etree.parse(filepath)

    @property
    def parsed_data(self):
        return self.tree


def connection_factory(filepath):#工厂方法,基于输入文件路径的扩展名返回一个JSONConnector或XMLConnector的实例

    if filepath.endswith('json'):
        connector = JSONConnector
    elif filepath.endswith('xml'):
        connector = XMLConnector
    else:
        raise ValueError('Cannot connect to {}'.format(filepath))
    return connector(filepath)


def connect_to(filepath):
    factory = None
    try:
        factory = connection_factory(filepath)
    except ValueError as ve:
        print(ve)
    return factory


def main():
    sqlite_factory = connect_to('/home/spark/下载/mpdp-code-master/chapter1/data/person.sq3')#确认异常处理是否有效,应返回“Cannot connect to /home/spark/下载/mpdp-code-master/chapter1/data/person.sq3
”
    print()

    xml_factory = connect_to('/home/spark/下载/mpdp-code-master/chapter1/data/person.xml')
    xml_data = xml_factory.parsed_data
    liars = xml_data.findall(".//{}[{}='{}']".format('person',
                                                     'lastName', 'Liar'))
    print('found: {} persons'.format(len(liars)))
    for liar in liars:
        print('first name: {}'.format(liar.find('firstName').text))
        print('last name: {}'.format(liar.find('lastName').text))
        [print('phone number ({})'.format(p.attrib['type']),
               p.text) for p in liar.find('phoneNumbers')]

    print()

    json_factory = connect_to('/home/spark/下载/mpdp-code-master/chapter1/data/donut.json')
    json_data = json_factory.parsed_data
    print('found: {} donuts'.format(len(json_data)))
    for donut in json_data:
        print('name: {}'.format(donut['name']))
        print('price: ${}'.format(donut['ppu']))
        [print('topping: {} {}'.format(t['id'], t['type'])) for t in donut['topping']]

if __name__ == '__main__':
    main()

输出

Cannot connect to /home/spark/下载/mpdp-code-master/chapter1/data/person.sq3

found: 2 persons
first name: Jimy
last name: Liar
phone number (home) 212 555-1234
first name: Patty
last name: Liar
phone number (home) 212 555-1234
phone number (mobile) 001 452-8819

found: 3 donuts
name: Cake
price: $0.55
topping: 5001 None
topping: 5002 Glazed
topping: 5005 Sugar
topping: 5007 Powdered Sugar
topping: 5006 Chocolate with Sprinkles
topping: 5003 Chocolate
topping: 5004 Maple
name: Raised
price: $0.55
topping: 5001 None
topping: 5002 Glazed
topping: 5005 Sugar
topping: 5003 Chocolate
topping: 5004 Maple
name: Old Fashioned
price: $0.55
topping: 5001 None
topping: 5002 Glazed
topping: 5003 Chocolate
topping: 5004 Maple

抽象工厂

问题

  • 创造一个游戏。至少包含两个游戏,一个面向孩子,一个面向成人;
  • 在运行时,基于用户输入,决定该创建哪个游戏并运行。

实现

class Frog:

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

    def interact_with(self, obstacle):
        print('{} the Frog encounters {} and {}!'.format(self,
                                                         obstacle, obstacle.action()))


class Bug:

    def __str__(self):
        return 'a bug'

    def action(self):
        return 'eats it'


class FrogWorld:

    def __init__(self, name):
        print(self)
        self.player_name = name

    def __str__(self):
        return '\n\n\t------ Frog World ———'

    def make_character(self):
        return Frog(self.player_name)

    def make_obstacle(self):
        return Bug()


class Wizard:

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

    def interact_with(self, obstacle):
        print('{} the Wizard battles against {} and {}!'.format(self, obstacle, obstacle.action()))


class Ork:

    def __str__(self):
        return 'an evil ork'

    def action(self):
        return 'kills it'


class WizardWorld:

    def __init__(self, name):
        print(self)
        self.player_name = name

    def __str__(self):
        return '\n\n\t------ Wizard World ———'

    def make_character(self):
        return Wizard(self.player_name)

    def make_obstacle(self):
        return Ork()


class GameEnvironment:

    def __init__(self, factory):
        self.hero = factory.make_character()
        self.obstacle = factory.make_obstacle()

    def play(self):
        self.hero.interact_with(self.obstacle)


def validate_age(name):
    try:
        age = input('Welcome {}. How old are you? '.format(name))
        age = int(age)
    except ValueError as err:
        print("Age {} is invalid, please try \
        again…".format(age))
        return (False, age)
    return (True, age)


def main():
    name = input("Hello. What's your name? ")
    valid_input = False
    while not valid_input:
        valid_input, age = validate_age(name)
    game = FrogWorld if age < 18 else WizardWorld
    environment = GameEnvironment(game(name))
    environment.play()

if __name__ == '__main__':
    main()

输出

Hello. What's your name? du
Welcome du. How old are you? 10


    ------ Frog World ———
du the Frog encounters a bug and eats it!


----------

Hello. What's your name? du
Welcome du. How old are you? 20


    ------ Wizard World ———
du the Wizard battles against an evil ork and kills it!

总结

两种模式都可以应用于一下场景:

  • 想要追踪对象的创建时;
  • 想要将对象的创建与应用解耦时;
  • 想要优化应用的性能和资源占用时。

工厂方法设计模式的实现,是一个不属于任何类的单一函数,负责单一种类对象的创建;抽象工厂设计模式的实现,是同属于单个类的许多个工厂方法用于创建一系列种类的相关对象。

发布了93 篇原创文章 · 获赞 97 · 访问量 40万+

猜你喜欢

转载自blog.csdn.net/duxu24/article/details/72331145