基本概念
FactoryMethod是一种创建性模式,它定义了一个创建对象的接口,但是却让子类来决定具体实例化哪一个类.当一个类无法预料要创建哪种类的对象或是一个类需要由子类来指定创建的对象时我们就需要用到Factory Method 模式了.简单说来,Factory Method可以根据不同的条件产生不同的实例,当然这些不同的实例通常是属于相同的类型,具有共同的父类.Factory Method把创建这些实例的具体过程封装起来了,简化了客户端的应用,也改善了程序的扩展性,使得将来可以做最小的改动就可以加入新的待创建的类. 通常我们将Factory Method作为一种标准的创建对象的方法,当发现需要更多的灵活性的时候,就开始考虑向其它创建型模式转化
简单分析
图1是Factory Method 模式的结构图,这里提供了一些术语,让我们可以进行更方便的描述:
- Product: 需要创建的产品的抽象类.
- ConcreteProduct: Product的子类,一系列具体的产品.
- Creator: 抽象创建器接口,声明返回Product类型对象的Factory Method.
- ConcreteCreator: 具体的创建器,重写Creator中的Factory Method,返回ConcreteProduct类型的实例.
图1: Factory Method 模式结构由此可以清楚的看出这样的平行对应关系: Product <====> Creator ; ConreteProduct <====> ConreteCreator
抽象产品对应抽象创建器,具体产品对应具体创建器.这样做的好处是什么呢?为什么我们不直接用具体的产品和具体的创建器完成需求呢?实际上我们也可以这样做.但通过Factory Method模式来完成,客户(client)只需引用抽象的Product和Creater,对具体的ConcreteProduct和ConcreteCreator可以毫不关心,这样做我们可以获得额外的好处:
- 首先客户端可以统一从抽象创建器获取产生的实例,Creator的作用将client和产品创建过程分离开来,客户不用操心返回的是那一个具体的产品,也不用关心这些产品是如何创建的.同时,ConcreteProduct也被隐藏在Product后面,ConreteProduct继承了Product的所有属性,并实现了Product中定义的抽象方法,按照Java中的对象造型(cast)原则,通过ConcreteCreator产生的ConcreteProduct可以自动的上溯造型成Product.这样一来,实质内容不同的ConcreteProduct就可以在形式上统一为Product,通过Creator提供给client来访问.
- 其次,当我们添加一个新的ConcreteCreator时,由于Creator所提供的接口不变,客户端程序不会有丝毫的改动,不会带来动一发而牵全身的灾难, 这就是良好封装性的体现.但如果直接用ConcreteProduct和ConcreteCreator两个类是无论如何也做不到这点的. 优良的面向对象设计鼓励使用封装(encapsulation)和委托(delegation),而Factory Method模式就是使用了封装和委托的典型例子,这里封装是通过抽象创建器Creator来体现的,而委托则是通过抽象创建器把创建对象的责任完全交给具体创建器ConcreteCreator来体现的.
现在,请再回头看看基本概念中的那段话,开始也许觉得生涩难懂,现在是不是已经明朗化了很多.
下面让我们看看在 Java 中如何实现Factory Method模式,进一步加深对它的认识.
具体实施
先说明一点,用Factory Method模式创建对象并不一定会让我们的代码更短,实事上往往更长,我们也使用了更多的类,真正的目的在于这样可以灵活的,有弹性的创建不确定的对象.而且,代码的可重用性提高了,客户端的应用简化了,客户程序的代码会大大减少,变的更具可读性.
- 标准实现: 这里我采用Bruce Eckel 用来描述OO思想的经典例子 Shape.这样大家会比较熟悉一些.我完全按照图1中所定义的结构写了下面的一段演示代码.这段代码的作用是创建不同的Shape实例,每个实例完成两个操作:draw和erase.具体的创建过程委托�oShapeFactory来完成.
1.a 首先定义一个抽象类Shape,定义两个抽象的方法.
abstractclassShape{
//勾画shape
publicabstractvoiddraw();
//擦去shape
publicabstractvoiderase();
publicStringname;
publicShape(StringaName){
name=aName;
}
}
1.b 定义 Shape的两个子类: Circle, Square,实现Shape中定义的抽象方法
//圆形子类
classCircleextendsShape{
publicvoiddraw(){
System.out.println("Itwilldrawacircle.");
}
publicvoiderase(){
System.out.println("Itwilleraseacircle.");
}
//构造函数
publicCircle(StringaName){
super(aName);
}
}
//方形子类
classSquareextendsShape{
publicvoiddraw(){
System.out.println("Itwilldrawasquare.");
}
publicvoiderase(){
System.out.println("Itwilleraseasquare.");
}
//构造函数
publicSquare(StringaName){
super(aName);
}
}
1.c 定义抽象的创建器,anOperation调用factoryMethod创建一个对象,并对该对象进行一系列操作.
abstractclassShapeFactory{
protectedabstractShapefactoryMethod(StringaName);
//在anOperation中定义Shape的一系列行为
publicvoidanOperation(StringaName){
Shapes=factoryMethod(aName);
System.out.println("Thecurrentshapeis:"+s.name);
s.draw();
s.erase();
}
}
1.d 定义与circle和square相对应的两个具体创建器CircleFactory,SquareFactory,实现父类的methodFactory方法
//定义返回circle实例的CircleFactory
classCircleFactoryextendsShapeFactory{
//重载factoryMethod方法,返回Circle对象
protectedShapefactoryMethod(StringaName){
returnnewCircle(aName+"(createdbyCircleFactory)");
}
}
//定义返回Square实例的SquareFactory
classSquareFactoryextendsShapeFactory{
//重载factoryMethod方法,返回Square对象
protectedShapefactoryMethod(StringaName){
returnnewSquare(aName+"(createdbySquareFactory)");
}
}
1.e 测试类:请注意这个客户端程序多么简洁,既没有罗嗦的条件判断语句,也无需关心ConcreteProduct和ConcreteCreator的细节(因为这里我用anOperation封装了Product里的两个方法,所以连Product的影子也没看见,当然把Product里方法的具体调用放到客户程序中也是不错的).
classMain{
publicstaticvoidmain(String[]args){
ShapeFactorysf1=newSquareFactory();
ShapeFactorysf2=newCircleFactory();
sf1.anOperation("Shapeone");
sf2.anOperation("Shapetwo");
}
}
运行结果如下:
The current shape is: Shape one (created by SquareFactory)
It will draw a square.
It will erase a square.
The current shape is: Shape two (created by CircleFactory)
It will draw a circle.
It will erase a circle.
- 参数化的Factory Method: 这种方式依靠指定的参数作为标志来创建对应的实例,这是很常见的一种办法.比如JFC中的BorderFactory就是个很不错的例子. 以下的这个例子是用字符串作为标记来进行判断的,如果参数的类型也不一样,那就可以用到过载函数来解决这个问题,定义一系列参数和方法体不同的同名函数,这里java.util.Calendar.getInstance()又是个极好的例子.参数化的创建方式克服了Factory Method模式一个最显著的缺陷,就是当具体产品比较多时,我们不得不也建立一系列与之对应的具体构造器. 但是在客户端我们必须指定参数来决定要创建哪一个类.
2.a 我们在第一种方法的基础上进行修改,首先自定义一个的异常,这样当传入不正确的参数时可以得到更明显的报错信息.
classNoThisShapeextendsException{
publicNoThisShape(StringaName){
super(aName);
}
}
2.b去掉了ShapeFactory的两个子类,改为由ShapeFactory直接负责实例的创建. ShapeFactory自己变成一个具体的创建器,直接用参数化的方法实现factoryMethod返回多种对象.
abstractclassShapeFactory{
privatestaticShapes;
privateShapeFactory(){}
staticShapefactoryMethod(StringaName,StringaType)throwsNoThisShape{
if(aType.compareTo("square")==0)
returnnewSquare(aName);
elseif(aType.compareTo("circle")==0)
returnnewCircle(aName);
elsethrownewNoThisShape(aType);
}
//在anOperation中定义Shape的一系列行为
staticvoidanOperation(StringaName,StringaType)throwsNoThisShape{
s=factoryMethod(aName,aType);
System.out.println("Thecurrentshapeis:"+s.name);
s.draw();
s.erase();
}
}
2.c 测试类:这里客户端必须指定参数来决定具体创建哪个类.这个例子里的anOperation是静态函数,可以直接引用.
classMain{
publicstaticvoidmain(String[]args)throwsNoThisShape{
ShapeFactory.anOperation("Shapeone","circle");
ShapeFactory.anOperation("Shapetwo","square");
ShapeFactory.anOperation("Shapethree","delta");
}
}
运行结果如下:
Thecurrentshapeis:Shapeone
Itwilldrawacircle.
Itwilleraseacircle.
Thecurrentshapeis:Shapetwo
Itwilldrawasquare.
Itwilleraseasquare.
Exceptioninthread"main"NoThisShape:delta
atShapeFactory.factoryMethod(ShapeFactory.java:10)
atShapeFactory.anOperation(ShapeFactory.java:15)
atMain.main(Main.java:5)
- 动态装载机制:
有的时候我们会把ConcreteProduct的实例传给创建器作为参数,这种情况下,如果在创建器里完成创建过程,就必须判断参数的具体类型(用instanceof),然后才能产生相应的实例,那么比较好的做法是利用Java的动态装载机制来完成这件事.比如:
我们得到一个Shape的子类s,但不知道具体是那个子类,就可以利用Class类自带的方法newInstance()得到实例
return (Shape)s.getClass().newInstance();
这种方法有兴趣得读者可以自己尝试,限于篇幅,不写具体代码出来了.
后话:
看完这篇文章后,相信读者对Factory Method模式有一个比较清楚的了解了.我想说的是,我们不仅应该关心一个具体的模式有什么作用,如何去实现这个模式,更应该透过现象看本质,不但知其然,还要知其所以然.要通过对模式的学习加深对面向对象思想的理解,让自己的认识得到升华.Factory Method模式看似简单,实则深刻.抽象,封装,继承,委托,多态,针对接口编程等面向对象中的概念都在这里得到了一一的体现.只有抓住了它的本质,我们才能够不拘于形式的灵活运用,而不是为了使用模式而使用模式.
参考资料
关于作者
|
|
|
刘湛,武汉大学信息与计算科学系学士,熟悉 Java 语言和 J2EE 思想,国内多个 Java 论坛版主,现致力于 J2EE 平台上的 eCRM 套件开发。你可以通过 jeru@163.net与他联系!
|
分享到:
相关推荐
在设计模式中,FactoryMethod也是比较简单的一个,但应用非常广泛,EJB,RMI,COM,CORBA,Swing中都可以看到此模式的影子,它是最重要的模式之一.在很多地方我们都会看到xxxFactory这样命名的类,那么,什么是FactoryMethod,...
Java常用设计模式(SingleTon、FactoryMethod、AbstractFactory)
JAVA设计模式-day2,请的行业大能讲得课程,涉及:创建模式(5种: 1、 工厂方法模式(Factory Method); 2、 抽象工厂模式; 3、 单例模式(Singleton) • 4、 建造者模式(Builder); 5、 原型模式(Prototype...
设计模式 t02FactoryMethod
2. 工厂方法模式(Factory Method) 3. 抽象工厂模式(Abstract Factory) 这三种模式从上到下逐步抽象,并且更具一般性。还有一种分类法,就是将简单工厂模式看为工厂方法模式的一种特例,两个归为一类。下面是使用...
各个设计模式的介绍,非常不错 Java与设计模式 设计模式之Factory -工厂模式设计模式之FACTORY METHOD -工厂模式設計模式之Builder -建造模式
- 23种设计模式 - 工厂方法模式(Factory Method) - 抽象工厂模式(Abstract Factory) - 单例模式(Singleton) - 建造者模式(Builder) - 原型模式(Prototype) - 代理模式(Proxy) - 适配器模式(Adapter) - 装饰...
本资源包汇总了Java中23种经典设计模式的详细介绍和使用示例,旨在帮助开发者系统性地学习和掌握设计模式在软件开发中的应用。这些设计模式分为三大类:创建型模式、结构型模式和行为型模式,每种模式都包括定义、...
主要内容有:Iterator-迭代器、Adapter(适配器)、Template Method(模板方法)、Factory Method(工厂方法)、Abstract Factory(抽象工厂)等。
《研磨设计模式》在内容上深入、技术上实用、和实际开发结合程度很高,书中大部分的示例程序都是从实际项目中简化而来,因此很多例子都可以直接拿到实际项目中使用。如果你想要深入透彻地理解和掌握设计模式,并...
《研磨设计模式》在内容上深入、技术上实用、和实际开发结合程度很高,书中大部分的示例程序都是从实际项目中简化而来,因此很多例子都可以直接拿到实际项目中使用。如果你想要深入透彻地理解和掌握设计模式,并...
《研磨设计模式》在内容上深入、技术上实用、和实际开发结合程度很高,书中大部分的示例程序都是从实际项目中简化而来,因此很多例子都可以直接拿到实际项目中使用。如果你想要深入透彻地理解和掌握设计模式,并...
创意设计模式 -- Abstract Factory - Done -- Builder - Done -- Factory Method -- Object Pool -- Prototype - Done -- Singleton - Done 结构设计模式 -- Adapter -- Bridge -- Composite -- Decorator - Done ...
适合Java设计模式期末考试选择题复习,形式如下: 10.(单选题)Facade(外观)模式的意图是 正确答案: A A.希望简化现有系统的使用方法,你需要定义自己的接口 B.将一个无法控制的现有对象与一个特定借口相匹配。 C....
《java设计模式(第2版)》通过一个完整的java项目对经典著作design patterns一书介绍的23种设计模式进行了深入分析与讲解,实践性强,却又不失对模式本质的探讨。本书创造性地将这些模式分为5大类别,以充分展现各个...
设计模式综合应用实例 设计模式综合应用实例 多人联机射击游戏 多人联机射击游戏中的设计模式应用(一) 多人联机射击游戏中的设计模式应用(二) 数据库同步系统 设计模式综合实例分析之数据库同步系统(一) 设计...
5、工厂方法模式FACTORY METHOD PATTERN 6、抽象工厂模式ABSTRACT FACTORY PATTERN 7、门面模式FACADE PATTERN 8、适配器模式ADAPTER PATTERN 9、模板方法模式TEMPLATE METHOD PATTERN 10、建造者模式BUILDER ...
FactoryMethod ( 工厂方法 ) Singleton ( 单态模式 ) Builder ( 建造者模式 ) Prototype ( 原型模式 ) Adapter ( 适配器模式 ) Bridge ( 桥接模式 ) Composite ( 组合模式 ) Decorator ( 装饰模式 ) Facade ...
1.工厂方法模式(Factory Method) 将程序中创建对象的操作,单独出来处理,创建一个产品的工厂接口,把实际的工作转移到具体的子类。大大提高了系统扩展的柔性,接口的抽象化处理给相互依赖的对象创建提供了最好的...