两年前的随笔,关于工厂方法和抽象工厂,和他们之间的区别。
先来看下简单工厂:简单工厂只要实现共有的接口就可以实现不同的产品。
1 public interface IHuman
2 {
3 void say();
4 }
5
6 public class Man : IHuman
7 {
8 public void say()
9 {
10 Console.WriteLine("哈喽,我是一个男人");
11 }
12 }
13
14 public class Woman : IHuman
15 {
16 public void say()
17 {
18 Console.WriteLine("嗨,我是一个女人");
19 }
20 }
21
22 public class Nuwa
23 {
24 public static IHuman MakeHuman(string humanType)
25 {
26 switch (humanType)
27 {
28 case "male": return new Man();
29 case "female": return new Woman();
30 default: throw new Exception();
31 }
32 }
33 }
34
35 public class Client
36 {
37 public static void Main()
38 {
39 IHuman aHuman = Nuwa.MakeHuman("female");
40 aHuman.say();
41 }
42 }
再来看下工厂方法:工厂方法重点在于产品怎么创建。【一个产品的具体实现】
1 public interface IHuman
2 {
3 void say();
4 }
5
6 public class Man : IHuman
7 {
8 public void say()
9 {
10 Console.WriteLine("哈喽,我是一个男人");
11 }
12 }
13
14 public class Woman : IHuman
15 {
16 public void say()
17 {
18 Console.WriteLine("嗨,我是一个女人");
19 }
20 }
21
22 public abstract class Nuwa
23 {
24 public abstract IHuman MakeHuman();
25 }
26
27 public class NuwaOnlyMakeMan : Nuwa
28 {
29 public override IHuman MakeHuman()
30 {
31 return new Man();
32 }
33 }
34
35 public class NuwaOnlyMakeWoman : Nuwa
36 {
37 public override IHuman MakeHuman()
38 {
39 return new Woman();
40 }
41 }
42
43 class Client
44 {
45 public static void Main()
46 {
47 Nuwa nuwa = new NuwaOnlyMakeWoman();
48 IHuman aHuman = nuwa.MakeHuman();
49 aHuman.say();
50 }
51 }
接下来看下抽象工厂:抽象工厂重点在于创建哪些产品。【实现不同的产品生产线】
1 public interface IAdult
2 {
3 void say();
4 }
5
6 public interface IChild
7 {
8 void say();
9 }
10
11 public class AdultMan : IAdult
12 {
13 public void say()
14 {
15 Console.WriteLine("我是一个成年男人,有点老了");
16 }
17 }
18
19 public class AdultWoman : IAdult
20 {
21 public void say()
22 {
23 Console.WriteLine("我是一个成年女人,老娘我不再年轻了");
24 }
25 }
26
27 public class Boy : IChild
28 {
29 public void say()
30 {
31 Console.WriteLine("我是一个男孩,我很年轻");
32 }
33 }
34
35 public class Girl : IChild
36 {
37 public void say()
38 {
39 Console.WriteLine("我是一个女孩,看好了,我是女孩呀");
40 }
41 }
42
43 public interface INuwa
44 {
45 IAdult MakeAdult();
46 IChild MakeChild();
47 }
48
49 public class NuwaOnlyMakeMale : INuwa
50 {
51 public IAdult MakeAdult()
52 {
53 return new AdultMan();
54 }
55 public IChild MakeChild()
56 {
57 return new Boy();
58 }
59 }
60
61 public class NuwaOnlyMakeFemale : INuwa
62 {
63 public IAdult MakeAdult()
64 {
65 return new AdultWoman();
66 }
67
68 public IChild MakeChild()
69 {
70 return new Girl();
71 }
72 }
73
74 class Client
75 {
76 public static void Main()
77 {
78 INuwa nuwa = new NuwaOnlyMakeFemale();
79 IChild aChild = nuwa.MakeChild();
80 aChild.say();
81 Console.Read();
82 }
83 }
//uml 类图 明天上传。
在代码设计时,我们有时候会困惑是采用工厂方法呢还是采用抽象工厂。
<<Head First Design Pattern>>第四章后面有这两个的比较对话,说的很清楚,下面是具体对话内容:
HeadFirst:哇,马上就要采访工厂模式中的两位老大了,这是我们的第一次接触啊,我现在心情很激动啊。
Factory Method:呃,你知道我自己是不太喜欢被你们把我和抽象工厂(Abstract Factory)混淆在一起。仅仅是因为我们都是工厂模式中的一员,所以把我们俩放在一起来采访吗,为什么不独自进行呢。
HeadFirst:你先别生气嘛,我想一起采访你们,这样做的目的就是想要帮助那些读者们消除你们俩谁是谁的混淆啊。你们俩确实有相同之处,而且我也听说了人们有时候在使用工厂模式的时候,会把你们俩给混淆了。
Abstract Factory:确实是这样啊,有时候我会被人们误认为是工厂方法(Factory Method),而且我知道工厂方法你也有类似的困惑。其实我们都很擅长让应用程序的高层模式在创建类的实例时无需依赖于这些类的具体实现。所以我能理解人们为什么有时会把我俩给混淆了。
Factory Method:呃,也太过简单地说我了吧。毕竟,我是让类来负责创建对象的工作而你是使用一堆的对象;这就是咱俩最根本的区别啊。
HeadFirst:等等,Factory Method您能不能对上面说的那个根本区别再深入解释下呢?
Factory Method:当然可以。抽象工厂和我都是用来产生对象的,这是我们的天职。但是我是通过继承。。。
Abstract Factory:。。。我是通过对象的组合。
Factory Method:说得很对。所以这就意味着,你们如果想要通过我产生对象的话,就要通过继承一个抽象类型然后在子类里覆盖那个抽象类的factory method。
HeadFirst:这factory method是干什么用的呢?
Factory Method:当然是用来产生一个(请大家注意是一个,我想这也很关键)对象的。我的意思是说,工厂方法模式的一个最核心的地方就是你们利用一个子类,让它来决定如何完成一个具体对象的生成工作。通过这种方式,客户端(调用者所在的类)只需要知道这个对象的抽象类型,而子类呢才关心这个抽象类型的真正实现类。所以呢,换句话说,我能分离客户端和具体的实现类。
Abstract Factory:我也能实现,只不过是我通过另外一种不同的方式罢了。
HeadFirst:继续,Abstract Factory。。。为我们谈谈有关对象组合的情况吧?
Abstract Factory:我提供了一个抽象类(通常来说是接口)来创建一个产品家族。这个抽象类的子类来定义这些产品是如何被生产的。为了使用这个工厂,你声明一个,然后再把一个子类通过参数传递,来对它赋值{也就是说,在一个客户端类里先声明一个抽象的工厂类,然后比如说可以在它的构造函数里留个参数是个抽象类型(抽象工厂类)的,在实例化这个客户端的时候把抽象工厂类的子类(也即是哪个产品族)传进来,从而在构造函数里完成对这个抽象类的实例化。}(在抽象类里的一组方法返回的都是抽象产品)所以呢,跟工厂方法一样,我也分离了客户端和它们要使用的究竟是哪种具体的产品。
HeadFirst:哦,我明白了,你提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
Abstract Factory:对。
HeadFirst:那如果说你要扩充这组相关或相互依赖的产品,也就是说增加另外一个成员呢?那样的话就必须改变你的接口了啊?
Abstract Factory:确实是这样,如果新的产品加进来了,我的接口必须改变,我知道人们都不喜欢这样做。。。
Factory Method:(窃笑)。。。
Abstract Factory:工厂方法,你在窃笑什么呢?
Factory Method:哦~~快快行动吧,那可是重要的事啊!改变你的接口那就意味着你必须深入到所以实现了这个接口的子类,然后挨个改变!这看起来可有很多事情要做啊。
Abstract Factory:是的,但是我有一个相对来说范围比较大的接口因为我习惯了从一开始就产生整个产品族。你只是生成一个产品,所以你不须要有一个大的接口,只需在你的抽象类里定义一个这样的方法就行了。
HeadFirst:抽象工厂,我听说你经常用一些factory method来实现你的具体工厂类。
Abstract Factory:嗯,这点我承认。我的那些具体工厂通常实现一个工厂方法来产生他们的具体产品。照我的情况来看,他们现在已经完全习惯产生产品。。。
Factory Method:。。。而按我的情况来看我通常在抽象生产者(角色,抽象类)里实现一部分代码来利用那些子类所产生的具体类(大概是说抽象的工厂类里,这是一个抽象类,不是接口的情况下,有一部分方法不是工厂方法,这些方法是留给那些所有子类用的,因为这是他们所共有的属性或行为)
HeadFirst:听起来你们俩都很擅长各自的工作。我肯定人们喜欢有一个选择的;毕竟,工厂是如此的有用,他们会在各种情况下恰当地使用工厂模式。你们都封装了具体对象的产生过程从而达到应用程序的松耦合而且不依赖于具体的实现,这是相当重要地啊,无论是使用工厂方法还是使用抽象工厂。在最后请你们分别说几句想说的话。
Abstract Factory:谢谢,请记住我,抽象工厂,在下面情况下请记住及时使用我:
一个系统要独立于它的产品的创建、组合和表示时。
一个系统要由多个产品系列中的一个来配置时。
当你要强调一系列相关的产品对象的设计以便进行联合使用时。
当你提供一个产品类库,而只想显示它们的接口而不是实现时。
Factory Method:我是工厂方法,遇到下面情况,不要犹豫地使用我:
当一个类不知道它所必须创建的对象的类的时候。
当一个类希望由它的子类来指定它所创建的对象的时候。
当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信 息局部化的时候。