天道不一定酬所有勤
但是,天道只酬勤
Hollis出品的全套Java面试宝典不来了解一下吗?

设计模式(六)——JDK中的那些工厂方法

Hollis出品的全套Java面试宝典不来了解一下吗?

新专题:设计模式,我会在博客(http://www.hollischuang.com)及微信公众号(hollischuang)同步更新,欢迎共同学习。

设计模式(五)——工厂方法模式中介绍了工厂方法模式。本文通过介绍JDK源码中用到的工厂方法,在上篇文章的基础上深入理解一下工厂方法。

再谈工厂方法

设计模式(五)——工厂方法模式中用整篇介绍了工厂方法模式。为什么要再谈呢?因为很多人走进了一个误区。认为工厂方法模式就是要严格包含抽象产品、具体产品、抽象工厂和具体工厂等角色。其实并不是这样的。

有时候也会创建不使用多态性创建对象的工厂方法,以得到使用工厂方法的其他好处。

如果抛开设计模式的范畴,“工厂方法”这个词也可以指作为“工厂”的方法,这个方法的主要目的就是创建对象,而这个方法不一定在单独的工厂类中。这些方法通常作为静态方法,定义在方法所实例化的类中。

每个工厂方法都有特定的名称。在许多面向对象的编程语言中,构造方法必须和它所在的类具有相同的名称,这样的话,如果有多种创建对象的方式(重载)就可能导致歧义。工厂方法没有这种限制,所以可以具有描述性的名称。举例来说,根据两个实数创建一个复数,而这两个实数表示直角坐标或极坐标,如果使用工厂方法,方法的含义就非常清晰了。当工厂方法起到这种消除歧义的作用时,构造方法常常被设置为私有方法,从而强制客户端代码使用工厂方法创建对象。

class Complex {
     public static Complex fromCartesianFactory(double real, double imaginary) {
         return new Complex(real, imaginary);
     }
     public static Complex fromPolarFactory(double modulus, double angle) {
         return new Complex(modulus * cos(angle), modulus * sin(angle));
     }
     private Complex(double a, double b) {
         //...
     }
}

Complex product = Complex.fromPolarFactory(1, pi);

上面的代码也可以叫做使用了工厂方法模式。同样是定义了一个工厂方法,方法的作用就是生成一个新的对象。

JDK中的工厂方法模式

看过前面的介绍和上一篇文章的介绍,相信读者对工厂方法有了一定的认识,那么能不能试着回答这样一个问题:什么情况下应该使用工厂方法模式?

其实这个问题很简单。很多时候我们在自己的代码中会不自觉的会使用到工厂方法模式。考虑以下情况:

创建对象需要大量重复的代码。

创建对象需要访问某些信息,而这些信息不应该包含在复合类中。

创建对象的生命周期必须集中管理,以保证在整个程序中具有一致的行为。

遇到上面的情况时,你是不是会"很自觉"的把创建对象的代码封装到一个方法中呢?这个方法就是工厂方法。其实这就是工厂方法的思想。

在JDK中,也有很多使用工厂方法模式的代码。下面就介绍几个典型的用法。

Collection中的iterator方法

java.util.Collection接口中定义了一个抽象的iterator()方法,该方法就是一个工厂方法。

对于iterator()方法来说Collection就是一个根抽象工厂,下面还有List等接口作为抽象工厂,再往下有ArrayList等具体工厂。

java.util.Iterator接口是根抽象产品,下面有ListIterator等抽象产品,还有ArrayListIterator等作为具体产品。

使用不同的具体工厂类中的iterator方法能得到不同的具体产品的实例。

collection-iterator-uml

JDBC数据库开发

在使用JDBC进行数据库开发时,如果数据库由MySQL改为Oracle或其他,则只需要改一下数据库驱动名称就可以,其他都不用修改(前提是使用的都是标准SQL语句)。或者在Hibernate框架中,更换数据库方言也是类似道理。

连接邮件服务器框架

如果需要设计一个连接邮件服务器的框架,那么就要考虑到连接邮件服务器有几种方式:POP3SMTPHTTP。就可以定义一个连接邮件服务器接口,在此接口中定义一些对邮件操作的接口方法,把这三种连接方式封装成产品类,实现接口中定义的抽象方法。再定义抽象工厂和具体工厂,当选择不同的工厂时,对应到产生相应的连接邮件产品对象。采用这种工厂方法模式的设计,就可以做到良好的扩展性。比如某些邮件服务器提供了WebService接口,只需要增加一个产品类和工厂类就可以了,而不需要修改原来代码。

其他工厂方法

除上面介绍的典型的使用工厂方法模式的用法外,在JDK中还有几处使用了工厂方法来创建对象。其中包括:

java.lang.Proxy#newProxyInstance()
java.lang.Object#toString()
java.lang.Class#newInstance()
java.lang.reflect.Array#newInstance()
java.lang.reflect.Constructor#newInstance()
java.lang.Boolean#valueOf(String)
java.lang.Class#forName()

读者感兴趣可以找出来看一看,这些方法都是用于返回具体对象。上面大部分方法都和反射有关,因为反射创建对象的过程比较复杂,封装成工厂方法更易于使用。

参考资料

工厂方法模式

赞(4)
如未加特殊说明,此网站文章均为原创,转载必须注明出处。HollisChuang's Blog » 设计模式(六)——JDK中的那些工厂方法
Hollis出品的全套Java面试宝典不来了解一下吗?

评论 2

  1. #1

    我又来了,您高兴吗?!

    10273484889年前 (2016-04-15)回复
  2. #2

    java.lang.Proxy#newProxyInstance()这个不是简单工厂模式吗?

    小菜鸟5年前 (2019-08-28)回复

HollisChuang's Blog

联系我关于我