c# - 工厂方法模式和抽象工厂模式如何选择

标签 c# design-patterns factory-pattern

我知道以前有人问过类似的问题。在过去的几天里,我已经阅读了很多关于此的内容,我想我现在可以理解设计和代码流方面的差异。令我困扰的是,这两种模式似乎都可以解决同一组问题,而没有真正的理由选择一个或另一个。 当我试图自己解决这个问题时,我尝试实现一个小例子(从我在“Head First:Design patterns”一书中找到的那个开始)。 在这个例子中,我尝试两次解决同一个问题:一次只使用“工厂方法模式”,另一次使用“抽象工厂模式”。我会向您展示代码,然后我会提出一些意见和问题。

通用接口(interface)和类

public interface IDough { }
public interface ISauce { }
public class NYDough : IDough { }
public class NYSauce : ISauce { }
public class KNDough : IDough { }
public class KNSauce : ISauce { }

纯工厂方法模式

// pure Factory method pattern
public abstract class Pizza
{
    protected IDough Dough { get; set; }
    protected ISauce Sauce { get; set; }
    protected abstract IDough CreateDough();
    protected abstract ISauce CreateSauce();
    public void Prepare()
    {
        Dough = CreateDough();
        Sauce = CreateSauce();
        // do stuff with Dough and Sauce
    }
    public void Bake() { }
    public void Cut() { }
    public void Box() { }
}

public class NYCheesePizza : Pizza
{
    protected override IDough CreateDough()
    {
        return new NYDough();
    }

    protected override ISauce CreateSauce()
    {
        return new NYSauce();
    }
}

public class KNCheesePizza : Pizza
{
    protected override IDough CreateDough()
    {
        return new KNDough();
    }

    protected override ISauce CreateSauce()
    {
        return new KNSauce();
    }

}

public abstract class PizzaStore
{
    public void OrderPizza(string type)
    {
        Pizza pizza = CreatePizza(type);
        pizza.Prepare();
        pizza.Bake();
        pizza.Cut();
        pizza.Box();
    }
    public abstract Pizza CreatePizza(string type);
}

public class NYPizzaStore : PizzaStore
{
    public override Pizza CreatePizza(string type)
    {
        switch (type)
        {
            case "cheese":
                return new NYCheesePizza();
            default:
                return null;
        }
    }
}

public class KNPizzaStore : PizzaStore
{

    public override Pizza CreatePizza(string type)
    {
        switch (type)
        {
            case "cheese":
                return new KNCheesePizza();
            default:
                return null;
        }
    }
}

纯抽象工厂模式

public interface IIngredientFactory
{
    IDough createDough();
    ISauce createSauce();
}

public class NYIngredientFactory : IIngredientFactory
{
    public IDough createDough()
    {
        return new NYDough();
    }

    public ISauce createSauce()
    {
        return new NYSauce();
    }
}

public class KNIngredientFactory : IIngredientFactory
{
    public IDough createDough()
    {
        return new KNDough();
    }

    public ISauce createSauce()
    {
        return new KNSauce();
    }
}

public class Pizza
{
    IDough Dough { get; set; }
    ISauce Sauce { get; set; }
    IIngredientFactory IngredientFactory { get; set; }

    public Pizza(IIngredientFactory ingredientFactory)
    {
        IngredientFactory = ingredientFactory;
    }

    public void Prepare()
    {
        Dough = IngredientFactory.createDough();
        Sauce = IngredientFactory.createSauce();
    }
    public void Bake() { }
    public void Cut() { }
    public void Box() { }
}

public interface IPizzaFactory
{
    Pizza CreatePizza(string type);
}

public class NYPizzaFactory : IPizzaFactory
{
    public Pizza CreatePizza(string type)
    {
        switch (type)
        {
            case "cheese":
                return new Pizza(new NYIngredientFactory());
            default:
                return null;
        }
    }
}

public class KNPizzaFactory : IPizzaFactory
{
    public Pizza CreatePizza(string type)
    {
        switch (type)
        {
            case "cheese":
                return new Pizza(new KNIngredientFactory());
            default:
                return null;
        }
    }
}

public class PizzaStore
{
    IPizzaFactory PizzaFactory { get; set; }

    public PizzaStore(IPizzaFactory pizzaFactory)
    {
        PizzaFactory = pizzaFactory;
    }

    public void OrderPizza(string type)
    {
        Pizza pizza = PizzaFactory.CreatePizza(type);
        pizza.Prepare();
        pizza.Bake();
        pizza.Cut();
        pizza.Box();
    }
}

如果我使用了模式定义,我会为 PizzaStore 选择“工厂方法模式”(因为它只构建一种类型的对象,Pizza)和“抽象工厂模式” IngredientFactory。无论如何,另一个设计原则指出你应该“优先组合而不是继承”,这表明我应该始终使用“抽象工厂模式”。

我的问题是:首先我应该选择“工厂方法模式”的原因是什么?

编辑

让我们看一下第一个实现,即使用工厂方法模式的实现。 Jesse van Assen 建议这是一个模板方法模式而不是工厂方法模式。我不相信这是对的。 我们可以将第一个实现分为两部分:第一部分处理 Pizza,第二部分处理 PizzaStore

1) 在第一部分中,Pizza 是依赖于某种具体的 Dough 和 Sauce 的客户端。为了将 Pizza 与我使用的具体对象分离,在 Pizza 类中,仅引用接口(interface)(IDoughISauce),我让Pizza 的子类决定具体的 DoughSauce 选择哪个。对我来说,这完全符合工厂方法模式的定义:

Define an interface for creating an object, but let the subclasses decide which class to instantiate. The Factory method lets a class defer instantiation to subclasses.

2) 第二部分中的PizzaStore 是客户端,它依赖于具体的Pizza。我应用了上面讨论的相同原则。

所以,为了更好地表达(我希望)我没有真正理解的是为什么这样说:

Factory Method pattern is responsible of creating products that belong to one family, while Abstract Factory pattern deals with multiple families of products.

正如您从我的示例中看到的(前提是它们是正确的:-))您可以使用两种模式进行相同的操作。

最佳答案

首先,GoF 设计模式书中的 2 条引述:

"Abstract Factory is often implemented with factory methods."

"Factory Methods are often called by template methods."

所以这不是在工厂方法和抽象工厂之间进行选择的问题,因为后者可以(并且通常)由前者实现。

抽象工厂的概念(正如 Amir 暗示的那样)是将几个始终在一起的具体类的创建组合在一起。在您的示例中,它们应该是 NY 种类的食物成分,而不是 KN 种类。

但是如果你想允许混搭(KN 面团和 NY 酱比萨有什么问题?)那么抽象工厂不是你的答案。在这种情况下,每个 Pizza 子类都应该决定它希望创建哪些具体类。

如果您不想允许这些类型的混合,您应该使用抽象工厂。

关于c# - 工厂方法模式和抽象工厂模式如何选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8952819/

相关文章:

c# - 在属性中的 Set 操作期间抛出的异常未被捕获

c# - 带有可选部分的正则表达式不会创建反向引用

c# - 如何在 ASP MVC 中实现工作单元、存储库和业务逻辑?

C++ 适当的指针成员初始化

java - 返回列表的工厂模式

c# - RijndaelManaged 返回空结果

c# - HTTP 错误 401.0 - 未经授权的错误消息

android - 按钮矩阵,如安全模式面板

php - 哪种设计模式适合这种情况?

php - 哪个类理想地分配属性 : User or UserFactory?