java设计模式2.工厂模式

工厂模式负责将大量拥有共同接口的类实例化,工厂模式可以动态决定将哪一个类实例化。

  • 简单工厂模式

又称静态工厂模式,就是一个工厂类根据传入的参数决定创建出哪一种产品类的实例。

  • 工厂类角色:工厂核心类,含有相关的业务判断逻辑,在客户端的直接调用下创建产品对象,往往由一个具体类实现。
  • 抽象产品角色:工厂创建的对象的父类或它们共同的接口,可以用一个接口或抽象类实现。
  • 具体产品角色:工厂所创建的对象的具体类型。

一个工厂类可以拥有多于一个的工厂方法,分别负责创建不同产品的对象。如果系统只有一个具体产品角色的话,可以省略掉抽象产品角色,有些情况下,工厂角色也可以由抽象产品角色扮演,如java.text.DataFormat。甚至三个角色全部合并,如在单例模式中,单例类具有一个静态工厂方法提供自身实例,即是抽象角色也是具体产品角色,但此外它要求构造器私有。

简单工厂模式的核心是工厂类,其含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,而客户端则可以免除直接创建产品对象的责任。但是当产品类有复杂的多层次等级结构时,工厂类只有它自己,这就是缺点,每次有新的产品加到系统中时,都必须修改工厂类。并且由于简单工厂模式使用静态工厂方法,无法由子类继承,因此,工厂角色无法形成基于继承的等级结构

  • 示例:DateFormat

如果看一下DateFormat就会发现,其实它是一个抽象类,但是却提供了很多的静态工厂方法,比如getDateInstance()为某种本地日期提供格式化,它由三个重载的方法构成。

抽象类不能有自己的实例,但是getDateInstance()并没有调用DateFormat的构造子来提供自己的实例,而是返回自己子类SimpleDateFormat的一个实例,并将它声明为DateFormat。这是最纯正的多态性原则运用,如果getDateInstance()是一个非静态的普通方法会怎样呢,如果要使用,客户端首先要获得这个类或子类的实例,如果客户端已取得子类的实例,又何必要这个工厂方法呢。DateFormat这样做是利用超类类型将具体产品类的类型隐藏起来(里氏替换,面向抽象),其好处是提供了系统的可扩展性,如果将来有新的具体子类被加到系统中来,那么工厂类可以将交给客户端的对象换成新的子类的实例,而对客户端没有任何影响。

  • 工厂模式

工厂模式中,工厂类不再负责所有的产品创建,而是将具体的产品创建工作交给子类去完成。自己成为抽象工厂角色,仅负责给出具体子类工厂必须实现的接口,而负责判断哪一个产品类应当被实例化。这种进一步抽象的结果,使工厂模式允许系统在不修改具体工厂角色的情况下,引进新的产品

  • 抽象工厂角色:工厂核心类,它是与应用程序无关的,任何在模式中创建对象的工厂类必须实现这个接口,通常由抽象类实现
  • 具体工厂角色:实现了工厂接口的具体类,含有与应用密切相关的业务逻辑,并受到应用程序的调用以创建产品对象。
  • 抽象产品角色:工厂所创建的对象的超类。
  • 具体产品角色:工厂所创建的对象的具体类型。

工厂模式的核心的是一个抽象工厂类,而简单工厂模式的核心是一个具体类,工厂模式允许很多具体工厂类从抽象工厂类中将创建行为继承下来,从而可以成为多个简单工厂模式的综合,进而推广了简单工厂模式。如果系统需要加入一个新的产品,那么所需要的就是向系统中加入一个这个产品类及它所对应的工厂类。没有必要修改客户端,也没有必要修改抽象工厂角色或者其他已有的具体工厂角色,对于新增的产品类而言,完全支持“开 – 闭”原则。

  • 示例:Collection

所有的java集合类都继承了java.util.Collection接口。这个接口规定了所有集合类都要提供一个iterator()方法,返回一个 Iterator 类型实例。一个具体的java集合对象会通过这个iterator()方法返回一个具体的Iterator类,可以看出,这个iterator()方法就是一个工厂方法。类似的,List接口也给出两个工厂方法,一个是继承自Collection的iterator()方法,另一个是listIterator()方法,返回一个 ListIterator 类型实例。有趣的是ListIterator 继承自Iterator 。

  • 示例:URL

创建一个URL对象很简单,只要将一个合法的URL传入到URL的构造子中即可URL url = new URL(“http://www.baidu.com”); URL对象提供一个叫做openConnection的工厂方法,这个方法返回一个URLConnection对象。而URLConnection对象代表一个与远程对象的连接。URLConnection是所有的代表应用系统与一个URL的连接对象的超类,使用URLConnection可以针对一个URL进行读写操作。显然,URL使用了工厂模式,以一个工厂方法openConnection返还一个URLConnection类型的对象。由于URLConnection是一个抽象类,因此返还的只能是其子类的实例。

  • 抽象工厂模式

假设一个系统需要一些产品对象,而这些产品又属于一个以上的产品等级结构。为了将消费这些产品对象的责任和创建这些产品对象的责任分割开来,可以引进抽象工厂模式。如果使用工厂模式处理的话,就必须有多个独立的工厂族,如果这些产品族的等级结构相同,使用同一个工厂族也可以处理这些产品族的创建问题,其实只是对这些独立的工厂族做了进一步的抽象。

 

#笔记内容参考《java与模式》