关于c#:如何在Factory方法模式和抽象工厂模式之间进行选择

How to choose between Factory method pattern and Abstract factory pattern

我知道以前也问过类似的问题。在过去的几天里,我读了很多关于这个的文章,我想我现在可以理解在设计和代码流方面的差异。令我困扰的是,这两种模式似乎都能解决相同的一组问题,而没有选择其中一个或另一个的真正原因。当我试图自己解决这个问题时,我试图实现一个小例子(从我在"head first:design patterns"一书中找到的例子开始)。在这个例子中,我试图解决同一个问题两次:一次只使用"工厂方法模式",另一次使用"抽象工厂模式"。我会给你看代码,然后我会做一些评论和问题。

公共接口和类

1
2
3
4
5
6
public interface IDough { }
public interface ISauce { }
public class NYDough : IDough { }
public class NYSauce : ISauce { }
public class KNDough : IDough { }
public class KNSauce : ISauce { }

纯工厂方法模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// 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;
        }
    }
}

号纯抽象工厂模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
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选择"抽象工厂模式"。不管怎样,另一个设计原则是,您应该"喜欢组合而不是继承",这意味着我应该始终使用"抽象工厂模式"。

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

编辑

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

1)在第一部分中,Pizza是依赖某种混凝土面团和酱汁的客户。为了将pizza与我使用的具体对象分离,在Pizza类中,只引用接口(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-souce做的披萨有什么问题?)那么抽象工厂不是你的答案。在这种情况下,每个比萨饼子类都应该决定要创建哪些具体的类。

如果你不想允许这种混合,你应该去抽象工厂。


如果您需要两个相关的工厂方法来做相同的决策,那么最好先在抽象工厂中进行分组。

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