这是否可以被视为工厂方法模式(或等效模式)?

2024-09-29 17:22:14 发布

您现在位置:Python中文网/ 问答频道 /正文

在我正在学习的一门课程中,一个PizzaStore使用SimplePizzaFactory类处理具体的比萨饼实例化,描述如下: enter image description here

在本课程中,通过介绍需要为PizzaStore提供额外级别的特殊性以及提供相同类型的Pizza(Viggie、Cheese等)但以NY风格和Chicago风格的能力来介绍factory方法模式,因此我们有了一组新的子类(NYSTYLEVIGGEIPIZA,NYStyleCheesePizza,…芝加哥风格VIGGEIPIZA,芝加哥风格CHEESEPIZZA,…)

讲师介绍的解决方案是使用工厂方法模式,如下所示:

(统一建模语言)

enter image description here

用python重新编写的代码:

# Pizzas Subclasses are defined elsewhere
from abc import ABC, abstractmethod

class PizzaStore(ABC):
    @abstractmethod
    def create_pizza(self):
        pass

    def order_pizza(self,type_of_pizza):
        type_of_pizza = type_of_pizza.lower()
        pizza = self.create_pizza(type_of_pizza)
        pizza.prepare()
        pizza.bake()
        pizza.box()
        return pizza


class NYPizzaStore(PizzaStore):
    def create_pizza(self, type_of_pizza):
        if type_of_pizza == "cheese":
            pizza = NYStyleCheesePizza()
        
        elif type_of_pizza == "pepperoni":
            pizza = NYStylePepperoniPizza()

        elif type_of_pizza == "clam":
            pizza = NYStyleClamPizza()

        elif type_of_pizza == "viggie":
            pizza = NYStyleViggiePizza()
        else:
            raise Exception("You need to specify a type of NY pizza.")   
        return pizza


class ChicagoPizzaStore(PizzaStore):
    def create_pizza(self,type_of_pizza):
        if type_of_pizza == "cheese":
            pizza = ChicagoStyleCheesePizza()
        elif type_of_pizza == "pepperoni":
            pizza = ChicagoStylePepperoniPizza()

        elif type_of_pizza == "clam":
            pizza = ChicagoStyleClamPizza()

        elif type_of_pizza == "viggie":
            pizza = ChicagoStyleViggiePizza()
        else:
            raise Exception("You need to specify a type of NY pizza.")
        
        return pizza


# ===== Driver Code =====
# NY store
ny_pizza_store = NYPizzaStore()
ny_pizza_store.order_pizza("Cheese")
ny_pizza_store.order_pizza("Pepperoni")


print()


# Chicago store
chicago_pizza_store = ChicagoPizzaStore()
chicago_pizza_store.order_pizza("Cheese")
chicago_pizza_store.order_pizza("Pepperoni")

在跳转到工厂方法之前,我尝试了以下设计,我保持了PizzaStore的原样,并用两个新类替换了SimpleFactoryPizzaNYPizzaFactoryChicagoPizzaFactory

enter image description here

用python重新编写的代码:

class NYPizzaFactory():
    def create_pizza(self,type_of_pizza):
        if type_of_pizza == "cheese":
            pizza = NYStyleCheesePizza()
        elif type_of_pizza == "pepperoni":
            pizza = NYStylePepperoniPizza()

        elif type_of_pizza == "clam":
            pizza = NYStyleClamPizza()

        elif type_of_pizza == "viggie":
            pizza = NYStyleViggiePizza()
        else:
            raise Exception("You need to specify a type of NY pizza.")
        
        return pizza

class ChicagoPizzaFactory():
    def create_pizza(self,type_of_pizza):
        if type_of_pizza == "cheese":
            pizza = ChicagoStyleCheesePizza()
        elif type_of_pizza == "pepperoni":
            pizza = ChicagoStylePepperoniPizza()

        elif type_of_pizza == "clam":
            pizza = ChicagoStyleClamPizza()

        elif type_of_pizza == "viggie":
            pizza = ChicagoStyleViggiePizza()
        else:
            raise Exception("You need to specify a type of NY pizza.")
        
        return pizza

# PizzaStore is the same as before

class PizzaStore:
    def __init__(self, pizza_factory_obj):
        self.pizza_factory_obj = pizza_factory_obj

    def order_pizza(self,type_of_pizza):
        type_of_pizza = type_of_pizza.lower() 
        pizza = self.pizza_factory_obj.create_pizza(type_of_pizza)
        pizza.prepare()
        pizza.bake()
        pizza.box()
        return pizza

# ===== Driver Code ======
# NY Store
ny_pizza_factory = NYPizzaFactory()
ny_pizza_store = PizzaStore(ny_pizza_factory)
ny_pizza_store.order_pizza("Cheese")
print()
ny_pizza_store.order_pizza("Pepperoni")
print()

# Chicago Store
chicago_pizza_factory = ChicagoPizzaFactory()
chicago_pizza_store = PizzaStore(chicago_pizza_factory)
chicago_pizza_store.order_pizza("Cheese")
print()
chicago_pizza_store.order_pizza("Pepperoni")

我知道工厂方法允许类将实例化延迟到其子类,其中这些子类将包括“工厂方法”的实现

问题1:

  • 根据定义,我的解决方案不被视为工厂模式吗?与所代表的工厂方法相比,我尝试的方法有哪些区别和缺点

问题2:

工厂方法结构由以下UML概括:(来自课程材料)

enter image description here

在《设计模式:可重用面向对象软件的元素》一书中,工厂方法模式的结构通过以下UML描述:

enter image description here

  • 工厂和产品之间的箭头表示课程材料中的“聚合”,而书中的UML图表示“依赖关系”(我想),哪一个表示正确的关系,为什么

Tags: of方法storeselffactory工厂deftype
2条回答

您最近描述的模式是抽象工厂模式;有几个工厂实现继承自同一个抽象工厂。在回答问题1时,这当然是工厂模式的一个变体

对于问题2,聚合与依赖关系实际上是一个风格问题。GoF对依赖性的使用(逻辑上)比聚合弱(即工厂依赖产品是比工厂聚合产品弱的概念)。两者都能传达信息,即两者都有效

就个人而言,我更喜欢依赖性,因为我不认为工厂实际上聚合了产品。对于聚合来说,想象一辆汽车聚合车轮。这与工厂和产品之间的关系并不是一个平行的概念。一旦产品被创造出来,工厂就与之无关了。继续这个例子,一旦一家汽车制造厂制造了一辆汽车,汽车就会离开工厂,再也不会回来,因此很难说汽车是制造它的工厂的一部分。然而,这是我的看法

我认为课程材料图表中的聚合是错误的。客户机将聚合(抽象)工厂,而不是相反,同样,工厂将聚合产品。我也不完全清楚为什么客户机不会直接引用产品,因为工厂中的关键是抽象对象的创建,而不是使用

Q1:您的实现是一个工厂吗

工厂方法模式旨在

define an interface for creating an object, but let the subclass decide which class to instantiate - (GoF, page 107).

您的设计和重新实现正是这样做的,并且是工厂

更详细的参数

在重新编写的解决方案中,根据图表,PizzaStore是某种上下文,可以使用NYPizzaFactoryChicagoPizzaFactory或两者兼用。您的代码比UML更清晰,因为您在构建时将工厂注入到存储中

你们的工厂似乎都是生产产品实例的具体创造者。每个混凝土创造者都会制作一套不同的混凝土比萨饼。单独来看,您的每个XxxPizzaFactory似乎对应于一个混凝土工厂,该FactoryMethod()被称为create_pizza()

图和代码中唯一缺少的是保证工厂是可互换的,允许它们从更一般的PizzaFactory继承。幸运的是,Python的动态类型可以处理缺少相同基类的情况。但出于维护目的,使用UML和Python更好地构造具有显式子类化的类

工厂还是抽象工厂?

每个具体工厂都可以创建不同类型的Pizza这一事实是被称为“参数化工厂方法”GoF的模式的变体,第110页)。因此,它确实是工厂模式,只是create_pizza()接受一个参数,该参数指定要实例化的具体比萨饼

这不是一个抽象工厂,因为抽象工厂旨在创建相关或从属产品的系列。家族中的每种产品都有其特定的工厂方法。如果您有几个create方法,比如create_pizza(), create_dessert(), create_wine(),那么这里就是这种情况。这里的情况并非如此,因为每个工厂只生产一种产品

问题2:聚合还是依赖

首先,GoF不使用UML(参见GoF,第363页)。本书撰写时,UML尚未正式出版:

有趣的是,OMT、Booch和Objectory是三种主要的OO符号,它们被合并以创建UML

从UML的角度来看

  • ConcreteCreatorConcreteProduct之间的关系是^{} dependency。事实上,在CreatorProduct之间也应该存在«create»依赖关系

  • FactoryProduct之间不应该有聚合,也不应该有关联(除非产品会跟踪创建它的工厂,或者工厂会保留它创建的所有产品的列表)

  • 关于side of the agregation有一个问题:您可以在ClientFactory之间使用聚合,但是在客户端使用菱形。尽管如此,虽然从根本上讲这并不是错误的,但是simple association更能代表这两个类之间的关系

其他信息:

PS:我使用了GoF来指代“设计模式:可重用面向对象软件的元素”

相关问题 更多 >

    热门问题