шаблон проектирования python - шаблон фабричного метода

задняя часть Python Шаблоны проектирования продукт

题目: Допустим, у вас есть магазин пиццы, есть функции включают в себя下订单,做 pizza, как будет написан ваш код?

def order_pizza():
    pizza = Pizza()
    pizza.prepare()
    pizza.bake()
    pizza.cut()
    pizza.box()
    return pizza

Но теперь у вас есть проблема, вашей пиццерии нужно больше пиццы, поэтому теперь вам нужно добавить некоторый код, чтобы определить подходящий тип пиццы, а затем сделать эту пиццу:

def order_pizza(pizza_type):  # 现在把 pizza 的类型传入 order_pizza()

    # 根据 pizza 类型,我们实例化正确的具体类,然后将其赋值给 pizza 实例变量
    if pizza_type == 'cheese':
        pizza = CheesePizza()
    elif pizza_type == 'greek':
        pizza = GreekPizza()
    elif pizza_type == 'pepperoni':
        pizza = PepperoniPizza()
    # 一旦我们有了一个 pizza,需要做一些准备(擀面皮、加佐料),然后烘烤、切片、装盒
    pizza.prepare()
    pizza.bake()
    pizza.cut()
    pizza.box()
    return pizza

Но после нескольких дней практики вы обнаружите, что клиентам нравится ClamPizza, Veggie Pizza и греческая пицца, но никто не любит греческую пиццу.В это время вам нужно изменить код:

def order_pizza(pizza_type):  # 现在把 pizza 的类型传入 order_pizza()

    # 根据 pizza 类型,我们实例化正确的具体类,然后将其赋值给 pizza 实例变量
    if pizza_type == 'cheese':
        pizza = CheesePizza()
    # elif pizza_type == 'greek':  # greek pizza 不再出现在菜单
    #     pizza = GreekPizza()
    elif pizza_type == 'pepperoni':
        pizza = PepperoniPizza()
    # 新加了 clam pizza 和 veggie pizza
    elif pizza_type == 'clam':
        pizza = ClamPizza()
    elif pizza_type == 'veggie':
        pizza = VeggiePizza()

    #  一旦我们有了一个 pizza,需要做一些准备(擀面皮、加佐料),然后烘烤、切片、装盒
    pizza.prepare()
    pizza.bake()
    pizza.cut()
    pizza.box()
    return pizza

Теперь вы обнаружили проблему, order_pizza() создает экземпляр конкретногоPizza 类, а order_pizza() не закрыт для модификации, поэтому каждый раз, когда добавляется новая пицца, код order_pizza() необходимо модифицировать. В настоящее время лучше абстрагировать создание объекта Pizza.Измененный код выглядит следующим образом:

# 把创建对象的代码从 order_pizza 方法中抽离
def create_pizza(pizza_type):
    # 根据 pizza 类型,我们实例化正确的具体类,然后将其赋值给 pizza 实例变量
    if pizza_type == 'cheese':
        pizza = CheesePizza()
    elif pizza_type == 'pepperoni':
        pizza = PepperoniPizza()
    elif pizza_type == 'clam':
        pizza = ClamPizza()
    elif pizza_type == 'veggie':
        pizza = VeggiePizza()
    return pizza

def order_pizza(pizza_type):  # 现在把 pizza 的类型传入 order_pizza()
    # 这里使用 create_pizza() 方法创建 pizza 类
    pizza = create_pizza(pizza_type)

    #  一旦我们有了一个 pizza,需要做一些准备(擀面皮、加佐料),然后烘烤、切片、装盒
    pizza.prepare()
    pizza.bake()
    pizza.cut()
    pizza.box()
    return pizza

Простой заводской шаблон

Давайте извлечем код, создающий объект пиццы, в новый метод, назовем этот новый метод工厂.

工厂обрабатывает детали создания объектов, как только выcreate_pizza,order_pizza()становится клиентом этого объекта. Когда вам нужна пицца, вы просто говорите фабрике, какую пиццу вы хотите, и пусть она ее готовит.

Теперь метод order_pizza() заботится только о том, чтобы получить пиццу с фабрики, эта пицца реализует интерфейс Pizza, поэтому он может вызыватьprepare()(准备),bake()(烘烤),cut()(切片),box()(装盒)

问:Теперь вы можете спросить, какая польза от того, что этот код выглядит более сложным? Похоже, он просто перенес проблему на другой объект.
答:Теперь кажется, что order_pizza простоcreate_pizzaКлиент , другие клиенты (например, меню магазина пиццы PizzaShopMenu) также могут использовать эту фабрику для получения пиццы. Оберните код создания пиццы в класс, и когда вы внесете изменения позже, вам нужно будет изменить только эту часть кода.

Здесь наша фабрикаcreate_order()это простой метод, использование методов для определения простого фабричного метода обычно называется简单工厂模式(简单工厂больше похоже на идиому программирования, чем на шаблон проектирования).

Переработанный класс PizzaStore

В приведенном выше кодеorder_pizzaЭто код клиента, но чтобы сделать нашу пиццерию более масштабируемой, здесь нам нужно изменить код клиента:

class SimplePizzaFactory:

    def create_pizza(self, pizza_type):
        ...
        return pizza

class PizzaStore:
    def order_pizza(self, pizza_type):  # 现在把 pizza 的类型传入 order_pizza()
        factory = SimplePizzaFactory()
        pizza = factory.create_pizza(pizza_type)
        ...
        return pizza

    # 下边是其他可能用到的方法

В этом коде мы инкапсулируем метод (create_pizza) в класс (SimplePizzaFactory), чтобы фабрика могла通过继承来改变创建方法的行为, и при этом также может улучшить расширяемость фабричного метода.

Теперь взглянем на диаграмму классов нашей пиццерии:

pizza店类图
Диаграмма классов пиццерии

Ограничения шаблона Simple Factory

недостаток

  • Поскольку фабричный класс концентрирует в себе всю логику создания продукта, он нарушает принцип высокого связного распределения ответственности: если он не работает должным образом, это повлияет на всю систему.
  • Расширить систему сложно.После добавления нового продукта логика фабрики должна быть изменена.При наличии многих типов продуктов логика фабрики может быть слишком сложной, что не способствует расширению и обслуживанию системы. .

сцены, которые будут использоваться

  • Фабричные классы отвечают за создание меньшего количества объектов
  • Клиент знает только параметры, переданные в фабричный класс, и не заботится о том, как создать объект (логика); клиенту не нужно заботиться о деталях создания или даже имени класса, ему нужно знать только параметры, соответствующие типу.

Чтобы преодолеть эти ограничения, давайте посмотрим на工厂方法模式

Шаблон фабричного метода

Теперь у нас новая проблема.После того как мы создаем пиццерию,кто-то хочет присоединиться,но мы также хотим контролировать процесс производства пиццы.Как этого добиться?

Во-первых, чтобы использовать фреймворк для пиццерии, все, что нам нужно сделать, это поставитьcreate_pizza()метод вернутьPizzaStoreclass, но этот метод необходимо реализовать один раз в каждом подклассе. в настоящее времяPizzaStoreКод:

class PizzaStore:

    def create_pizza(self, pizza_type):
        # 每个需要子类实现的方法都会抛出NotImplementedError
        # 我们也可以把 PizzaStore 的 metaclass 设置成 abc.ABCMeta
        # 这样的话,这个类就是真正的抽象基类
        raise NotImplementedError()

    def order_pizza(self, pizza_type):  # 现在把 pizza 的类型传入 order_pizza()

        pizza = self.create_pizza(pizza_type)

        #  一旦我们有了一个 pizza,需要做一些准备(擀面皮、加佐料),然后烘烤、切片、装盒
        pizza.prepare()
        pizza.bake()
        pizza.cut()
        pizza.box()
        return pizza

Таким образом мы объявляем фабричный метод. Этот фабричный метод используется для обработки создания объектов и инкапсуляции поведения создания в подклассе, так что код родительского класса в клиентской программе можно успешно отделить от кода создания объекта подкласса.

Причина, по которой мы вернули create_pizza обратно в PizzaStore, состоит в том, чтобы позволить подклассам, наследующим этот метод, нести ответственность за определение своих собственныхcreate_pizza()метод. Теперь давайте посмотрим на диаграмму подклассов PizzaStore:

здесьNYStlyePizzaStoreиChicagoStylePizzaStoreнеобходимо определить собственноеcreate_pizzaметод.

Теперь посмотрите на полный код:

#! -*- coding: utf-8 -*-

class Pizza:

    name = None
    dough = None
    sauce = None
    toppings = []

    def prepare(self):
        print("Preparing %s" % self.name)
        print("Tossing dough...")
        print("Adding sauce...")
        print("Adding toppings: ")
        for topping in self.toppings:
            print("  %s" % topping)

    def bake(self):
        print("Bake for 25 minutes at 350")

    def cut(self):
        print("Cutting the pizza into diagonal slices")

    def box(self):
        print("Place pizza in official PizzaStore box")

    def __str__(self):
        return self.name


class NYStyleCheesePizza(Pizza):

    name = "NY Style Sauce and Cheese Pizza"
    dough = "Thin Crust Dough"
    sauce = "Marinara Sauce"
    toppings = ["Grated", "Reggiano", "Cheese"]


class ChicagoStyleCheesePizza(Pizza):

    name = "Chicago Style Deep Dish Cheese Pizza"
    dough = "Extra Thick Crust Dough"
    sauce = "Plum Tomato Sauce"
    toppings = ["Shredded", "Mozzarella", "Cheese"]

    def cut(self):
        print("Cutting the pizza into square slices")


class PizzaStore:
    def create_pizza(self, pizza_type):
        # 每个需要子类实现的方法都会抛出NotImplementedError
        # 我们也可以把 PizzaStore 的 metaclass 设置成 abc.ABCMeta
        # 这样的话,这个类就是真正的抽象基类
        raise NotImplementedError()

    def order_pizza(self, pizza_type):  # 现在把 pizza 的类型传入 order_pizza()

        pizza = self.create_pizza(pizza_type)

        #  一旦我们有了一个 pizza,需要做一些准备(擀面皮、加佐料),然后烘烤、切片、装盒
        pizza.prepare()
        pizza.bake()
        pizza.cut()
        pizza.box()
        return pizza

class NYStylePizzStore(PizzaStore):
    def create_pizza(self, pizza_type):
        # 根据 pizza 类型,我们实例化正确的具体类,然后将其赋值给 pizza 实例变量
        if pizza_type == 'cheese':
            pizza = NYStyleCheesePizza()
        return pizza


class ChicagoStylePizzaStore(PizzaStore):
    def create_pizza(self, pizza_type):
        # 根据 pizza 类型,我们实例化正确的具体类,然后将其赋值给 pizza 实例变量
        if pizza_type == 'cheese':
            pizza = ChicagoStyleCheesePizza()
        return pizza


def main():
    nystore = NYStylePizzStore()
    pizza = nystore.order_pizza('cheese')
    print("goodspeed ordered a %s" % pizza)

    print("*" * 100)
    chicago_store = ChicagoStylePizzaStore()
    pizza = chicago_store.order_pizza('cheese')
    print("goodspeed ordered a %s" % pizza)


if __name__ == '__main__':
    main()

Здесь заводский метод create_pizza () напрямую бросаетNotImplementedError, это делается для того, чтобы заставить подклассы переопределить метод create_pizza(), который вызовет исключение, если не будет переопределен.NotImplementedError.
Конечно, вы также можете поставить PizzaStore'smetaclassустановлен вabc.ABCMetaВ этом случае класс является настоящим абстрактным базовым классом.

Теперь давайте посмотрим на диаграмму классов паттерна фабричный метод:

工厂方法模式类图
Диаграмма класса шаблона фабричного метода

Класс продукта и класс создателя на самом деле являются параллельными классами, и их отношения следующие:

Определение шаблона фабричного метода

Благодаря приведенному выше введению мы можем получить приблизительное определение шаблона фабричного метода:

существует工厂方法模式Родительский класс фабрики отвечает за определение общедоступного интерфейса для создания объектов продукта, в то время как подкласс фабрики отвечает за создание конкретных объектов продукта Цель этого состоит в том, чтобы отложить создание экземпляра класса продукта в подклассе фабрики, то есть через класс factory subclass, чтобы определить, какой конкретный класс продукта должен быть создан.

Шаблон фабричного метода может инкапсулировать создание экземпляров конкретных типов, а абстрактный Creator предоставляет способ создания объектов.工厂方法. В абстрактном Creator любой другой реализованный метод может использовать этот метод для блокировки производимого продукта, но только подклассы фактически реализуют этот фабричный метод и создают продукт.

На следующем рисунке показана принципиальная диаграмма классов шаблона фабричного метода:

工厂方法模式类图
Диаграмма класса шаблона фабричного метода

Преимущества шаблона фабричного метода

  • Фабричные методы централизуют создание объектов в одном месте, упрощая отслеживание объектов.
  • Шаблон фабричного метода может помочь нам сдвинуть реализацию продукта с使用середина解耦. Добавление продукта или изменение реализации продукта не повлияет на Создателя.
  • Еще одним преимуществом использования шаблона фабричных методов является то, что при добавлении в систему нового продукта нет необходимости изменять абстрактную фабрику и интерфейс, предоставляемый абстрактным продуктом, нет необходимости изменять клиент и не нужно изменять другие бетонные заводы и бетонные изделия, но нужно только добавить бетонный завод и конкретные продукты на нем. Таким образом, масштабируемость системы становится очень хорошей, полностью соответствующей принципу «открыто-закрыто».

Фабричные методы могут при необходимости создавать новые объекты, улучшая производительность и использование памяти. Если вы непосредственно создаете экземпляр класса для создания объекта, вам необходимо выделять дополнительную память каждый раз, когда вы создаете новый объект.

简单工厂и工厂方法разница между

Простая фабрика обрабатывает все вещи на месте (create_pizza), а заводский метод заключается в создании структуры, которая позволяет подклассам решать, как реализовать. Например, в заводском методе метод order_pizza () предоставляет общую структуру для создания метода Pizza, Ordeer_Pizza (), опирается на фабрику для создания бетонного класса и создать фактическую пиццу. Какая изготовленная пицца достигается путем наследования пиццастора. но简单工厂Он просто инкапсулирует объект и не обладает гибкостью фабричного метода.

Пример использования фабричного шаблона в приложении на Python

Модуль форм Django использует шаблон фабричного метода для создания полей формы. WTForm также использует шаблон фабричного метода. Шаблон фабричного метода также используется в различных частях соединения с базой данных sqlalchemy.

Суммировать

Основная идея паттерна фабричный метод состоит в том, чтобы определить общедоступный интерфейс для создания объектов, и фабрика, а не клиент, решает, какой класс необходимо создать.Обычно он используется при построении общей структуры системы. Шаблон фабричного метода кажется относительно простым, но его коннотация чрезвычайно глубока Теории объектно-ориентированного проектирования, такие как абстракция, инкапсуляция, наследование, делегирование, полиморфизм и т. д., были хорошо отражены, и сфера применения очень широкий.

Ссылаться на


Наконец, поблагодарите мою подругу за ее поддержку.

Добро пожаловать в подписку (April_Louisa) купи мне фанту
欢迎关注
Добро пожаловать, чтобы следовать
请我喝芬达
купи мне фанту