题目
: Допустим, у вас есть магазин пиццы, есть функции включают в себя下订单
,做 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), чтобы фабрика могла通过继承来改变创建方法的行为
, и при этом также может улучшить расширяемость фабричного метода.
Теперь взглянем на диаграмму классов нашей пиццерии:
Ограничения шаблона Simple Factory
недостаток
- Поскольку фабричный класс концентрирует в себе всю логику создания продукта, он нарушает принцип высокого связного распределения ответственности: если он не работает должным образом, это повлияет на всю систему.
- Расширить систему сложно.После добавления нового продукта логика фабрики должна быть изменена.При наличии многих типов продуктов логика фабрики может быть слишком сложной, что не способствует расширению и обслуживанию системы. .
сцены, которые будут использоваться
- Фабричные классы отвечают за создание меньшего количества объектов
- Клиент знает только параметры, переданные в фабричный класс, и не заботится о том, как создать объект (логика); клиенту не нужно заботиться о деталях создания или даже имени класса, ему нужно знать только параметры, соответствующие типу.
Чтобы преодолеть эти ограничения, давайте посмотрим на工厂方法模式
Шаблон фабричного метода
Теперь у нас новая проблема.После того как мы создаем пиццерию,кто-то хочет присоединиться,но мы также хотим контролировать процесс производства пиццы.Как этого добиться?
Во-первых, чтобы использовать фреймворк для пиццерии, все, что нам нужно сделать, это поставитьcreate_pizza()
метод вернутьPizzaStore
class, но этот метод необходимо реализовать один раз в каждом подклассе. в настоящее время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.
Суммировать
Основная идея паттерна фабричный метод состоит в том, чтобы определить общедоступный интерфейс для создания объектов, и фабрика, а не клиент, решает, какой класс необходимо создать.Обычно он используется при построении общей структуры системы. Шаблон фабричного метода кажется относительно простым, но его коннотация чрезвычайно глубока Теории объектно-ориентированного проектирования, такие как абстракция, инкапсуляция, наследование, делегирование, полиморфизм и т. д., были хорошо отражены, и сфера применения очень широкий.
Ссылаться на
- «Шаблоны проектирования Head First»
- «Освоение шаблонов проектирования Python»
- "Практика программирования на Python"
- Третья серия шаблонов проектирования Python: шаблон метода создания фабрики
Наконец, поблагодарите мою подругу за ее поддержку.
Добро пожаловать в подписку (April_Louisa) | купи мне фанту |
---|---|