Topic: 关于Factory, Abstract Factory, Factory Method, 和Builder模式的思考

  Print this page

1.关于Factory, Abstract Factory, Factory Method, 和Builder模式的思考 Copy to clipboard
Posted by: polygoncell
Posted on: 2005-11-19 20:56

选这4个模式在一起讨论首先是因为她们的功能比较类似,都是用来制造对象实例的,从归类来说,他们都属于制造类模式(creational patterns),其次她们们在工作中比较常用,由于功能太过相似,往往导致在某个实际问题上让人举棋不定,似乎选哪个都可以解决问题,可是真的选择某个模式后,又会发现不是完全合适。今天我们就来讨论讨论在什么情况下选择什么模式来解决问题比较合适。

考虑到不是所有的朋友都对以上提到的4种模式都了如指掌,在开始讨论之前先简单的介绍一下这4个模式,对这4种模式熟悉的朋友也可以顺便回顾一下。请注意,这里我只会做简短的介绍,如果要比较深入地了解她们的话,还请去看模式相关的书籍,比较浅显易懂的我推荐 “Head First Design Patterns”。如果要在工作中反复参考的我推荐 “Applied Java Patterns”。那本经典的GOF Design Patterns由于写的时间比较早,举的例子不太适合现在的软件开发,我个人认为初学者或者是没有太多时间的朋友没有必要去读那本书,尽管她的确是经典。

Factory Pattern

中文叫工厂模式, 这个是我们在面向对象编程中最常用的模式之一了,她的主要功能就是制造对象,也正是这个原因才叫她为工厂模式,工厂干什么?生产产品。通常情况而言某个工厂所生产的产品总是一个系列的不同种类,大体上相同,细节上有差异。

图1 展示了一个非常简单的例子,通常CarFactory类会提供下列方法来生产车辆, 如代码片断1所示:

public class CarFactory {

public Car createBusinessCar() {….}

public Car createSportCar() {…}

}

代码片断 1



图1 Factory Pattern

Abstract Factory Pattern

中文叫抽象工厂模式,顾名思义,就是把工厂模式在进一步抽象化,进一步细化。我们继续沿用上面的例子,不过这次增加产品的种类,如图2所示。由于我们增加了一层分类,当我们要生产某种车的时候就需要询问要哪种车, 商用还是跑车?不然的话就要增加create方法,如果分类多了,create方法就会成几何数量增长。

public class CarFactory {

public Car createBusinessBMWCar() {….}

public Car createBusinessBenzCar() {…}

public Car createSportBMWCar() {….}

public Car createSportBenzCar() {…}

}

代码片断 2



图2 bad Factory Pattern

从面向对象的角度来讲,不是很好的解决方法,需要进一步抽象。结果就是把CarFactory进行抽象,然后针对不同品牌的车产生不同的工厂。 如图3



图3 Abstract Factory Pattern

这个时候每个工厂类仍然只需要2个方法,如代码片断1所示,用户会在不同需要的情况下得到不同的工厂对象,进而生产出需要的Car。不论这里工厂类如何实现,客户端的代码可以始终不变,类似这样:getCarFactory().createBusinessCar()。

以上两个模式多用于:

1 。 客户端需要依赖制造对象的细节。
2. 一系列类似的对象需要被制造出来。
3. 同种对象不同实体需要在不同的地点不同是时间被制造出来。

Factory Method Pattern

中文叫工厂方法模式, 通常是用于当某个类的功能主要是针对生产出来的对象提供一些相关服务,而且这些对象有共同的接口,至于对象具体是什么,留给她的子类来决定。这样解释起来比较晦涩难懂,我们还是沿用生产汽车的例子,不过不再用工厂,而是改用销售部门,因为销售部门主要为生产出来的车提供相关服务的,比方说,折扣,售后服务等等。代码如代码片断3 所示, 这里CarStore是个抽象类,如何生产需要的车将由子类来进一步实现, 比方说BMWStore就会生产出BMW。图4展示了相关的UML图, 总体看起来图4和图3非常相似, 但是从实现原理和实际应用上来说两者是完全不同的, 图3 Abstract Factory是针对Interface的多种不同的实现,具体使用的

时候是“组和”,用英语术语表达就是“composition”。 而图4 Factory Method是子类对抽象父类继承,进而实现父类的抽象方法, 具体使用的时候是”继承”, 用英语术语表达就是”inheritance”。 也就是很多OO书里说谈到的“is a? or has a?”的问题, composition指的就是has a, 而inheritance指的就是is a。

public abstract class CarStore {

// Factory method

protected abstract Car createBusinessCar();

protected abstract Car createSportCar();



public void sell() {

createBusinessCar();

discount(…);

....

}

public double discount(Customer customer) {….}

public void service() {…}

}

代码片断 3

这个模式多半会和另一个模式Template Method一起使用,事实上代码片断3中方法sell() 就是template Method。具体关于template method pattern的详细讲解已不属于本文的讨论主题 ,感兴趣的朋友请看相关书籍。



图4 Factory Method

Builder Pattern

中文叫生成器模式,我觉得叫构造模式更贴切,通常用于提供尽可能简单的接口来生成比较复杂的对象,这个复杂的对象通常包含有很多其他的对象。有些人认为Builder和Factory Method很相似,有时候是可以互换的,这样理解是错误的。这两个模式的侧重点是不同的,Builder侧重的是构造复杂对象,而且经常是使用到composite模式; Factory Method侧重的是生产各种各样不同的对象,这些对象通常都是比较简单的,一般而言,Factory Method不会和composite联合使用。总的来说这两个模式是相辅相成的,决不能视为同类。具体原因我会在讨论中加以阐述。图5 展示了Builder概念图。



图5 Builder Pattern

考虑到使用composite模式,我们使用另外一个例子,做饭,比较简单,常见,人人都做过,解释起来应该比较好懂。我们先定义好“食品”是对所有吃的物品的概括,做好的炸酱面是食品,煮好的面条是食品,做好的酱是食品,做酱用的料也是食品。当我们去餐馆叫吃炸酱面时,我们只希望要一碗做好的炸酱面, 我们可不会希望对小二说煮面,切黄瓜丝,打鸡蛋,剁肉末,熬酱,等等。我们只希望说:“小二,来碗炸酱面。” 这时候就需要用到builder, builder会提供一个简单的方法createNoodleWithSource() — 做炸酱面,当顾客点吃炸酱面后,builder就会在内部制造一系列的食品,比方说,煮面,切黄瓜丝,打鸡蛋,剁肉末,熬酱,等等。而这些细节,作为顾客是不需要费心的。

讨论

4种模式都已经简要的介绍完了,到这里大家应该对她们有了大概地了解。从根本上来说,每一个模式都不难理解,真正困难的是选择,在什么情况下用哪个模式才是正确的? 每一个初学者碰到了实际的问题都会产生疑问,好像用那个模式都可以解决问题。我对以上4种模式进行了一番对比,并结合工作中的实际问题进行了思考,并且和同事们展开了讨论(这真是人生一大快事啊!)。我的建议是“毛主席教导我们要用发展的眼光来看待这个问题“ 。

一般来说,在软件开发过程中,总是把大的问题进行细化,然后从小处入手,逐渐发展壮大。也就是说最开始的时候遇到的问题往往很小,一个类就可以解决了,对于只需要生成简单对象的情况,使用Factory模式;对于需要生成复杂对象的情况,用builder模式,只需要写一个类,借口拉,抽象类拉,完全不需要!目前不需要担心松紧耦合的问题。进一步优化的话,可以写两个类,builder负责生成复杂的对象,而将所有关于生成简单对象的工作转交给Factory,用英语术语来表达的话叫“delegate”, 对应的模式叫Business Delegate(core J2EE Patterns)。

当系统发展壮大后, 需要生成很多种类的复杂对象,导致了需要很多builder来负责生成她们,这个时候就需要做两件事,第一是使用Abstract Factory模式,负责生成相对应的builder类,进而对各种复杂的对象生成进行系统的管理。第二是为各种类别的builder和Factory编写接口,然后利用refactoring将使用类的地方尽可能的替换为使用借口,也就是面向对象编程基本原理之一的“尽量针对接口编程,而不是针对实现类”。如果希望优化系统,减少对象实体的生成,可以视情况而定,采用Singleton模式。

请注意到目前为止,我们没有用到继承,这也是符合面向对象编程的原理的—组合优先于继承(composition, not inheritance)。但是当系统再进一步发展长大后,她已经不能再称为模块,而是成长为框架(framework)时,我们就要考虑适当的使用Factory Method模式了。基本的功能将在父类中加以实现,而具体的对象生成交由子类来完成。如果结合其他模式来理解的话,就是子类中生成对象的工作将转交给其他3中模式类们来完成。如果希望在运行状态(runtime)时动态切换相关的Builder或Factory的话,可以采用Strategy模式。不过,就像很多介绍面向对象编程的书籍建议的那样,不到万不得已不要使用继承,也就是说,切忌在系统还非常简单的情况下就贸然使用Factory Method。



图6 Big picture

到此为止所有4种模式都用上了,整个系统有如下优点:

1. 健壮,易于扩展,易于维护。
2. 针对接口,系统内部松散,解耦合。
3. 基本上避免了代码重复。

这样构件的系统里,我们用到了下列模式:

1. Factory Pattern

2. Abstract Factory Pattern

3. Builder Pattern

4. Singleton Pattern

5. Template Method Pattern

6. Composite Pattern

7. Strategy Pattern

8. Business Delegate Pattern

请关注我的Blog
http://spaces.msn.com/members/polygoncell/
http://blog.csdn.net/schnell/

2.Re:关于Factory, Abstract Factory, Factory Method, 和Builder模式的思考 [Re: polygoncell] Copy to clipboard
Posted by: floater
Posted on: 2005-11-20 02:29

another useful factory is the static factory, e.g., String.valueOf(...). This is used in the case when the creation process is dramatically different and you want the factory to be close to the object class.

3.Re:关于Factory, Abstract Factory, Factory Method, 和Builder模式的思考 [Re: polygoncell] Copy to clipboard
Posted by: polygoncell
Posted on: 2005-11-20 17:21

这个应该算不上是Pattern,只不过是将某些方法定义成static。最多只能算是Factory模式的变种。

4.Re:关于Factory, Abstract Factory, Factory Method, 和Builder模式的思考 [Re: polygoncell] Copy to clipboard
Posted by: floater
Posted on: 2005-11-20 22:52

The ideas behind patterns are more important than the behaviors - It's not just because it's static, it's because "the creation process is dramatically different - e.g., we could return different types in a hierarchy tree, or the creation process is very tied to the subclass". This is particularly true when the domain model is very complex, when the ordinary factory pattern could have ugly dependencies on the object classes.

5.Re:关于Factory, Abstract Factory, Factory Method, 和Builder模式的思考 [Re: polygoncell] Copy to clipboard
Posted by: polygoncell
Posted on: 2005-11-21 01:39

1. I cannot really understand your definition about the "static factory". actually, the reason, that you used, describes the power of the Factory. It is NOT the reason that we should ONLY use static Factory, that means any other Factory Patternns variants is not suitable. would you please introduce it in detail? maybe some codes example? Please do not hesitate to tell us. thanks.

2. The 4 Patterns that I compared here are coming from the GOF Design Patterns, which is a well known Patterns category in the world. Is the "static Factory" also a Pattern? whould you please give me the reference of it? Or it is only a variant of the Factory Pattern? If so, It is not a correct candidate for this discusstion.

6.Re:关于Factory, Abstract Factory, Factory Method, 和Builder模式的思考 [Re: polygoncell] Copy to clipboard
Posted by: polygoncell
Posted on: 2005-11-21 02:12

I have googled the whole web and untill now what I found is ONLY about "static factory method" not "static factory". And the discusstion is ONLY between "static fatory methods" and "contructors". So, as I have said, It is only a variant of the Factory Patern, Abstract Factory Pattern, and Factory Method Pattern. There is no such "static factory". whould you please give me a reference about "static factroy"?

7.Re:关于Factory, Abstract Factory, Factory Method, 和Builder模式的思考 [Re: polygoncell] Copy to clipboard
Posted by: floater
Posted on: 2005-11-21 03:33

I've never investigae this name on google, to be honest; I've just use this name to communicate with other folks, and it seems when we say this name, everyone knows what it means.

I think that static factory method may make more sense in the context because after all, it's an embedded method in classes, not an independent class.

yes, it's not in the GOF book, which was written 10 years ago. Since then, there are some advances, like M. Fowler's books, Gregor's book, etc. Hillside pattern group and other groups named many many more patterns than the orginal 23 patterns. Besides the definition of patterns in GOF, there is really no objective way(maybe alexendar's way) to define what's a pattern or not, so it's more of a perception. But I think no matter what, the logic is there to make an objective judgement(though personally I think it's a pattern because it appears in a lot of cases and the solution is working quite well). Another reason on this is the communication. I don't know when I am used to this name, but it seems working well for me. But different people have different perception, e.g., I know folks who don't think MVC is a pattern at all. So if I cause any confusion, sorry for that. I just want to say there is another place to put the creation related code, and it could help us isolate code if the context is appropriate.

I don't mean to use static factories only, as you mentioned in your #1, I just merely point out there is one more way to do it, in an appropriate context. My experience is as follows:

If the creation process is similar, then factory/abstract factory are proper, e.g., a DaoFactory just instantiates a Dao class and init(), this is a proper case to use a factory because every Dao class has an init() method, which hides the implementation details of different Dao class implementation. However, in some cases, it's hard to come up with this kind of unification. For example, I am working on a financial model, there is a security super class which models all the securities traded on the market. But the subclasses are dramatically different, a stock is nowhere close to a future contract. In this case, the creation of a stock is quite different than the creation of a future contract, besides the super class, they have nothing in common. So in this case, we don't want to put these two creations in the same factory, because the factory would know too much of the details and it could explode on number of lines of code. another scenario that I've seen is: several ways(or different inputs) to create an object with valid states. The key concern is the valid states.

I think Effective Java book also has an item on this one too, though it's not in the context of patterns, but in the context of object creation.

Here is a list when static factory is used with the same meaning:
http://blog.codefront.net/archives/2003/06/21/java-tip-2-static-factory-methods-vs-constructors/
http://6170.lcs.mit.edu/www-archive/Old-2002-Fall/lectures/lecture-13.pdf
http://blog.arendsen.net/index.php/2005/07/03/spring-instantiation-strategies/

If the consensus is to use static factory method as the name, that's fine with me, I really don't worry about that, since I care more on the creation process and how to communicate with others.

my 2 cents

8.Re:关于Factory, Abstract Factory, Factory Method, 和Builder模式的思考 [Re: polygoncell] Copy to clipboard
Posted by: polygoncell
Posted on: 2005-11-21 21:26

thanks for the useful reply! That is great! Now we got more Knowhow about the Factory.

I knew that the GOF book is old, I have also written it in my doc. But, The Patterns discussed here are written and rewritten in so many new books, they are not old. And the books that I suggested are written in the last few years, on in 2001, the other in oct. 2004. I knew there are many other Patterns category, but I have never heard from Martin Fowler that his category is ADVANCE one, than the GOF, as you said.

As you said "Another reason on this is the communication", that is absolutely correct. That is one of the important reason that we use the Patterns. Maybe there is no problem for you guys using "static factory" for the meaning of "static factory method", but, when you write your words down and try to communicate with anyone in the world, that will make confusion. The words, here used, should be globally acceptable and clearly understandable. The same reason that we can use "社经" for "社会经济学" ONLY in the campus. We use "CS" for "computer science" in IT branch but for "count striker" for gamers. We do not wanna any newbies get cofusion do we?

All your references show nothing else as making the methods static. And All benefits of "static factory method" we got here are the benefits of "static method". In my personal opinion, it is just a variant of factory Pattern and can not be accepted as a pattern. As I searched the whole web, I did not find anyone who says that the "static factory method" is another pattern.

Anyway, your reply is very useful. I really appreciate it.


   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1
客服电话 18559299278    客服信箱 714923@qq.com    客服QQ 714923