基本概念
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,定义两个抽象的方法.
abstract
class
Shape {
//
勾画shape
public
abstract
void
draw();
//
擦去 shape
public
abstract
void
erase();
public
String name;
public
Shape(String aName){
name
=
aName;
}
}
1.b 定义 Shape的两个子类: Circle, Square,实现Shape中定义的抽象方法
//
圆形子类
class
Circle
extends
Shape {
public
void
draw() {
System.out.println(
"
It will draw a circle.
"
);
}
public
void
erase() {
System.out.println(
"
It will erase a circle.
"
);
}
//
构造函数
public
Circle(String aName){
super
(aName);
}
}
//
方形子类
class
Square
extends
Shape {
public
void
draw() {
System.out.println(
"
It will draw a square.
"
);
}
public
void
erase() {
System.out.println(
"
It will erase a square.
"
);
}
//
构造函数
public
Square(String aName){
super
(aName);
}
}
1.c 定义抽象的创建器,anOperation调用factoryMethod创建一个对象,并对该对象进行一系列操作.
abstract
class
ShapeFactory {
protected
abstract
Shape factoryMethod(String aName);
//
在anOperation中定义Shape的一系列行为
public
void
anOperation(String aName){
Shape s
=
factoryMethod(aName);
System.out.println(
"
The current shape is:
"
+
s.name);
s.draw();
s.erase();
}
}
1.d 定义与circle和square相对应的两个具体创建器CircleFactory,SquareFactory,实现父类的methodFactory方法
//
定义返回 circle 实例的 CircleFactory
class
CircleFactory
extends
ShapeFactory {
//
重载factoryMethod方法,返回Circle对象
protected
Shape factoryMethod(String aName) {
return
new
Circle(aName
+
"
(created by CircleFactory)
"
);
}
}
//
定义返回 Square 实例的 SquareFactory
class
SquareFactory
extends
ShapeFactory {
//
重载factoryMethod方法,返回Square对象
protected
Shape factoryMethod(String aName) {
return
new
Square(aName
+
"
(created by SquareFactory)
"
);
}
}
1.e
测试类:请注意这个客户端程序多么简洁,既没有罗嗦的条件判断语句,也无需关心ConcreteProduct和ConcreteCreator的细节
(因为这里我用anOperation封装了Product里的两个方法,所以连Product的影子也没看见,当然把Product里方法的具体调用放
到客户程序中也是不错的).
class
Main {
public
static
void
main(String[] args){
ShapeFactory sf1
=
new
SquareFactory();
ShapeFactory sf2
=
new
CircleFactory();
sf1.anOperation(
"
Shape one
"
);
sf2.anOperation(
"
Shape two
"
);
}
}
运行结果如下:
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 我们在第一种方法的基础上进行修改,首先自定义一个的异常,这样当传入不正确的参数时可以得到更明显的报错信息.
class
NoThisShape
extends
Exception {
public
NoThisShape(String aName) {
super
(aName);
}
}
2.b去掉了ShapeFactory的两个子类,改为由ShapeFactory直接负责实例的创建. ShapeFactory自己变成一个具体的创建器,直接用参数化的方法实现factoryMethod返回多种对象.
abstract
class
ShapeFactory {
private
static
Shape s;
private
ShapeFactory() {}
static
Shape factoryMethod(String aName, String aType)
throws
NoThisShape{
if
(aType.compareTo(
"
square
"
)
==
0
)
return
new
Square(aName);
else
if
(aType.compareTo(
"
circle
"
)
==
0
)
return
new
Circle(aName);
else
throw
new
NoThisShape(aType);
}
//
在anOperation中定义Shape的一系列行为
static
void
anOperation(String aName, String aType)
throws
NoThisShape{
s
=
factoryMethod(aName, aType);
System.out.println(
"
The current shape is:
"
+
s.name);
s.draw();
s.erase();
}
}
2.c 测试类:这里客户端必须指定参数来决定具体创建哪个类.这个例子里的anOperation是静态函数,可以直接引用.
class
Main {
public
static
void
main(String[] args)
throws
NoThisShape{
ShapeFactory.anOperation(
"
Shape one
"
,
"
circle
"
);
ShapeFactory.anOperation(
"
Shape two
"
,
"
square
"
);
ShapeFactory.anOperation(
"
Shape three
"
,
"
delta
"
);
}
}
运行结果如下:
The current shape is: Shape one
It will draw a circle.
It will erase a circle.
The current shape is: Shape two
It will draw a square.
It will erase a square.
Exception in thread
"
main
"
NoThisShape: delta
at ShapeFactory.factoryMethod(ShapeFactory.java:
10
)
at ShapeFactory.anOperation(ShapeFactory.java:
15
)
at Main.main(Main.java:
5
)
- 动态装载机制:
有的时候我们会把ConcreteProduct的实例传给创建器作为参数,这种情况下,如果在创建器里完成创建过程,就必须判断参数的具体类型(用instanceof),然后才能产生相应的实例,那么比较好的做法是利用Java的动态装载机制来完成这件事.比如:
我们得到一个Shape的子类s,但不知道具体是那个子类,就可以利用Class类自带的方法newInstance()得到实例
return (Shape)s.getClass().newInstance();
这种方法有兴趣得读者可以自己尝试,限于篇幅,不写具体代码出来了.
后话:
看
完这篇文章后,相信读者对Factory
Method模式有一个比较清楚的了解了.我想说的是,我们不仅应该关心一个具体的模式有什么作用,如何去实现这个模式,更应该透过现象看本质,不但知其
然,还要知其所以然.要通过对模式的学习加深对面向对象思想的理解,让自己的认识得到升华.Factory
Method模式看似简单,实则深刻.抽象,封装,继承,委托,多态,针对接口编程等面向对象中的概念都在这里得到了一一的体现.只有抓住了它的本质,我
们才能够不拘于形式的灵活运用,而不是为了使用模式而使用模式.
参考资料
分享到:
相关推荐
在设计模式中,FactoryMethod也是比较简单的一个,但应用非常广泛,EJB,RMI,COM,CORBA,Swing中都可以看到此模式的影子,它是最重要的模式之一.在很多地方我们都会看到xxxFactory这样命名的类,那么,什么是FactoryMethod,...
根据给定文件内容,以下是关于Java设计模式的知识点说明: 1. 策略模式(Strategy Pattern)是一种行为设计模式,允许在运行时选择算法的行为。策略模式的意图是定义一系列算法,将每个算法封装起来,并使它们可以...
Java设计模式是面向对象编程中的重要概念,它们是解决常见问题的经验总结,为代码的可重用性、可维护性和可扩展性提供了指导。这里我们将深入探讨三种常见的Java设计模式:单例(Singleton)、工厂方法(Factory ...
《Java中的设计模式 - jdon》是一本深入探讨Java编程中设计模式的电子书,它主要聚焦于如何在实际开发中应用和理解这些经典的设计原则和模式。设计模式是软件工程中的一种最佳实践,它总结了在特定上下文中解决常见...
《设计模式——Java语言中的应用》是一本专为Java开发者深入理解面向对象设计而编写的经典书籍。设计模式是软件工程领域中经过实践验证的、解决常见问题的有效方案,它们代表了在特定上下文中,针对特定问题的最优...
在众多设计模式中,“工厂方法模式”(Factory Method Pattern)尤为突出,它是一种创建型设计模式,用于解决在类的实例化过程中,如何避免硬编码的问题,同时保持系统的灵活性与可扩展性。 #### 工厂方法模式的...
**三、Factory Method设计模式的意图** 使用工厂方法模式定义一个用于创建对象的接口,但让子类决定实例化哪个类。这种创建型设计模式允许一个类将实例化推迟到子类,增强了代码的灵活性和可维护性。 **四、通过...
以上就是Java设计模式的一些基本概念和应用,理解并熟练掌握这些模式对于编写高质量、易于维护的Java代码至关重要。通过阅读《设计模式——Java语言中的应用》这本书,你可以更深入地学习和掌握这些模式的细节及其在...
这篇名为"JAVA设计模式---100%推荐"的资源,可能是对Java设计模式的深入解析,旨在帮助开发者更好地理解和应用这些模式。 设计模式通常分为三类:创建型、结构型和行为型。创建型模式涉及对象的实例化过程,如单例...
### JAVA设计模式在JDK中的应用 #### 一、引言 在软件开发过程中,设计模式作为一套被广泛接受的解决方案,能够帮助开发者解决常见的设计问题。Java作为一门流行的编程语言,其标准库(JDK)中巧妙地融入了多种设计...
Java 与设计模式是软件开发中的重要主题,它们旨在提高代码的可维护性、灵活性和重用性。设计模式是对在软件设计中经常出现的问题及其解决方案的一种通用、可复用的描述。本篇将通俗易懂地介绍几种常见的设计模式,...
Java设计模式是软件开发中的一种最佳实践,它总结了在解决特定问题时程序员们经常采用的有效方法。这个“JAVA设计模式-chm版”资源显然包含了关于Java设计模式的详细信息,便于理解和应用。设计模式是对常见问题的...
《Java设计模式-图解-附代码》是一部全面介绍设计模式在Java语言中应用的教程,通过图示与实际代码结合的方式,深入浅出地解析了23种经典设计模式,旨在帮助开发者提高代码质量,增强程序的可维护性和扩展性。...
在Java中,设计模式的应用不仅限于上述介绍,还包括其他如命令模式(Command)、迭代器模式(Iterator)、备忘录模式(Memento)、模板方法模式(Template Method)等。这些模式在设计复杂系统时起着关键作用,比如...
### Java设计模式详解 #### 创建型模式 **1.1 工厂方法(Factory Method)** 工厂方法模式定义了一个创建对象的接口,但允许子类决定实例化哪一个类。这使得一个类的实例化可以被推迟到其子类。这种模式在以下...
本文将深入探讨Java设计模式,并通过具体的例子来阐述它们的应用。 首先,我们来看看创建型设计模式,它们主要处理对象的创建过程。单例模式(Singleton)确保一个类只有一个实例,并提供全局访问点。工厂方法模式...
Java设计模式是软件开发中的重要概念,它是一种在特定情境下解决问题的经验总结,可以提高代码的可读性、可维护性和可扩展性。本压缩包包含的源代码涵盖了多个经典的设计模式,接下来将对这些模式进行详细介绍。 1....
在Java编程中,设计模式是解决常见问题的模板化解决方案,它们是经验的结晶,能够提升代码的可读性、可维护性和复用性。本资源包主要涵盖了三种经典的设计模式:单例模式、工厂模式以及代理模式。下面将详细阐述这三...