1、工厂方法模式的引进
前面一章刚说过简单工厂模式,我们知道,简单工厂模式无论针对什么样的产品结构都采用以不变应万变的策略,就是只有一个工厂角色,所有的产品都通过这个万
能工厂类来创建,这个工厂类中包含了所有产品的创建逻辑,但是当我们系统中要增加一种新的产品的时候,那么我们就需要修改工厂类了,需要在工厂类中增加新
的产品创建逻辑,所以,这就不符合我们编写程序的"开-闭"原则。
所以就有了我们今天要说的工厂方法模式,首先,工厂方法模式中,核心工厂类不再负责具体产品的创建,而是将该职责交给了子类去做,这个核心类摇身一变变成
了抽象工厂角色,也就是所有具体工厂角色的父类,仅负责给出具体工厂子类必须实现的接口,而不去接触具体产品的创建细节了。
这么进一步抽象的操作就使得我们可以在不修改本身程序的前提下引进新的产品了,符合了我们程序设计的"开-闭"原则。
2、工厂方法模式的层级结构与各种角色
从上图可以分析出工厂方法模式的几个角色:
(1)抽象工厂角色(BaseFactory):这个角色是整个工厂方法模式的核心,所有创建对象的工厂类必须继承这个方法
(2)具体工厂角色(Factory_A):这个角色实现了抽象工厂角色的方法,具体工厂角色含有与应用密切相关的逻辑,负责创建对应的具体的产品,与具体产品
角色一一对应
(3)抽象产品角色(BaseProduct):工厂方法模式所创建的所有产品的超类型,也就是所有产品类的共有父类或者共同接口。
(4)具体产品角色(Product_A):继承或实现抽象产品角色。
客户端通过声明抽象工厂类对象,可获取到抽象工厂类对象的子类工厂,通过子类工厂创建产品的方法(显示返回抽象产品,实际返回具体产品)得到具体产品
类。当我们的系统中需要新增一种产品的时候,那我们不用修改原来的代码,只需要在系统中增加一个具体工厂类和一个与之相对应的具体产品类即可。
3、使用JAVA接口或者JAVA抽象类
我们也看到了,上面的抽象工厂类和抽象产品类我都是使用JAVA抽象类来实现的,实际中我们怎么选择呢。
如果具体工厂角色具有共同的逻辑,那么共同的逻辑就可以向上移动到抽象工厂角色中,这也就意味着抽象工厂角色应当由一个JAVA类实现,并且抽象工厂角色提
供默认的工厂方法。这个时候使用JAVA接口就不太合适,因为JAVA接口仅仅描述了方法的特征,而抽象类是可以描述出方法的具体逻辑实现的。
其实上面那个用例图没有必要用JAVA抽象类,因为他没有什么共有逻辑需要在父类中实现。
对于没有共有逻辑需要在父类中描述的,那么使用JAVA接口好一些,因为我们JAVA语言是一种单继承语言,它只能继承一个父类,所以使用继承的时候要慎重,
而JAVA接口没这个限制,一个类可以实现多个接口(这也是为什么已经有了抽象类的概念,还要弄出个接口概念的原因)。
实际使用中这个问题还是需要我们针对系统的实际情况仔细考虑一下的。
4、多态性的丧失和模式的退化
一个工厂方法模式的实现依赖于工厂角色和产品角色的多态性,在有些情况下,这个模式可以出现退化,其特点就是多态性的丧失。
工厂方法返还的应该是抽象类型而不是具体类型,只有这样才能保证针对产品的多态性。换言之,调用工厂方法的客户端总可以针对抽象编程,依赖于一个产品的抽象类型
而不是具体类型。
在特殊情况下,工厂方法仅返回一个具体产品类型,这个时候工厂方法就退化了,表现为针对产品角色的多态性的丧失,换言之,客户端知道了从工厂方法中获取的对象是
什么类型,这违背了工厂方法模式设计的原意,也就不是工厂方法模式了。
5、JAVA语言中工厂方法模式的例子
书中介绍的是Java集合类的迭代器,拿出来看一看
Collection接口中的一段代码:
/**
* Returns an iterator over the elements in this collection. There are no
* guarantees concerning the order in which the elements are returned
* (unless this collection is an instance of some class that provides a
* guarantee).
*
* @return an Iterator over the elements in this collection
*/
Iterator iterator();
继承Collction的List、Set等中有:
/**
* Returns an iterator over the elements in this list in proper sequence.
*
* @return an iterator over the elements in this list in proper sequence
*/
Iterator iterator();
接下来再看ArrayList中的代码:
/**
* Returns an iterator over the elements in this list in proper sequence.
*
* The returned iterator is fail-fast.
*
* @return an iterator over the elements in this list in proper sequence
*/
public Iterator iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
Itr类实现了Interator接口
public interface Iterator {
/**
* Returns {@code true} if the iteration has more elements.
* (In other words, returns {@code true} if {@link #next} would
* return an element rather than throwing an exception.)
*
* @return {@code true} if the iteration has more elements
*/
boolean hasNext();
/**
* Returns the next element in the iteration.
*
* @return the next element in the iteration
* @throws NoSuchElementException if the iteration has no more elements
*/
E next();
/**
* Removes from the underlying collection the last element returned
* by this iterator (optional operation). This method can be called
* only once per call to {@link #next}. The behavior of an iterator
* is unspecified if the underlying collection is modified while the
* iteration is in progress in any way other than by calling this
* method.
*
* @throws UnsupportedOperationException if the {@code remove}
* operation is not supported by this iterator
*
* @throws IllegalStateException if the {@code next} method has not
* yet been called, or the {@code remove} method has already
* been called after the last call to the {@code next}
* method
*/
void remove();
}
看全了代码我们就会明白这里是怎么应用的工厂模式了
其中Iterator是抽象产品角色,Itr是Iterator下面的一个具体产品角色,List类应该是抽象工厂角色,ArrayList应该是具体工厂角色。如果我们需要在List下自
定义一个集合类并给出相应的迭代方式,那么我们只需要添加一个实现List接口的集合类,然后在增加一个迭代类实现Iterator接口就可以了。并不需要去修改
JDK源码的内容,满足了开-闭原则。