【问题标题】:How to choose between Factory method pattern and Abstract factory pattern如何在工厂方法模式和抽象工厂模式之间进行选择
【发布时间】:2012-02-15 16:36:25
【问题描述】:

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

常用接口和类

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 and Sauce 的客户端。为了将 Pizza 与我使用的具体对象分离,在 Pizza 类中,仅引用接口(@98​​7654331@ 和 ISauce),我让 Pizza 的子类决定哪个具体的 Dough 和 @987654335 @ 选择。对我来说,这完全符合工厂方法模式的定义:

定义一个用于创建对象的接口,但让子类决定实例化哪个类。 Factory 方法允许类将实例化推迟到子类。

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

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

工厂方法模式负责创建属于一个系列的产品,而抽象工厂模式处理多个产品系列。

正如您从我的示例中看到的(只要它们是正确的 :-))您可以使用两种模式来实现相同的东西。

【问题讨论】:

标签: c# design-patterns factory-pattern


【解决方案1】:

首先,引用 GoF 设计模式书的两句话:

“抽象工厂通常用工厂方法实现。”

“工厂方法通常被模板方法调用。”

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

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

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

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

【讨论】:

  • 抱歉,我可能完全不懂你的意思,但我不明白抽象工厂如何不允许你所谓的“混合与匹配”。您始终可以定义另一个从 IIngredientFactory 继承并返回您想要混合的具体类型的工厂。
  • 嘿,我自己还远不是设计模式专家 :) 从技术上讲,你可以做任何事情,但它不会被视为抽象工厂。抽象工厂的思想是将具体对象分组到家庭。如果您确实想要混合,我根本不会使用子类化,因为它可能导致类膨胀。我可能会使用某种构建器 - Pizza 类将使用某种标识符指定它想要的组件类型(NY 面团、KN 酱),并且构建器将负责创建具体对象。
【解决方案2】:

如果你想要几个相关的工厂方法来做同样的决定,那么最好在抽象工厂中进行分组。

我会说你的第一个实现不是工厂方法。工厂方法不是抽象的,它们有参数决定根据它们实例化什么。

【讨论】:

  • 感谢您花时间回答。我认为,在工厂方法中,方法应该是抽象的,因为您希望在子类中实现它们。这是模式的要求。另一方面,关于参数,我不完全确定这是一个要求。
  • 您使用的模式是模板方法,而不是工厂方法。
  • @JessevanAssen :谢谢,您可能启发了我,现在甚至 Amir 的回答对我来说也更有意义。我不知道模板方法模式,我将进一步研究它,稍后我会发布一些内容。
  • mm 我还不相信,我做了一些编辑以更好地解释我的意思。我希望您有时间阅读并分享您的想法。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-11
  • 1970-01-01
  • 1970-01-01
  • 2017-07-31
相关资源
最近更新 更多