1、工厂方法模式的引进
前面一章刚说过简单工厂模式,我们知道。简单工厂模式不管针对什么样的产品结构都採用以不变应万变的策略,就是仅仅有一个工厂角色,全部的产品都通过这个万
能工厂类来创建,这个工厂类中包括了全部产品的创建逻辑,可是当我们系统中要添加一种新的产品的时候。那么我们就须要改动工厂类了,须要在工厂类中添加新
的产品创建逻辑,所以,这就不符合我们编敲代码的"开-闭"原则。
所以就有了我们今天要说的工厂方法模式,首先,工厂方法模式中。核心工厂类不再负责详细产品的创建,而是将该职责交给了子类去做。这个核心类摇身一变变成
了抽象工厂角色,也就是全部详细工厂角色的父类,仅负责给出详细工厂子类必须实现的接口。而不去接触详细产品的创建细节了。
这么进一步抽象的操作就使得我们能够在不改动本身程序的前提下引进新的产品了,符合了我们程序设计的"开-闭"原则。
2、工厂方法模式的层级结构与各种角色
从上图能够分析出工厂方法模式的几个角色:
(1)抽象工厂角色(BaseFactory):这个角色是整个工厂方法模式的核心,全部创建对象的工厂类必须继承这种方法
(2)详细工厂角色(Factory_A):这个角色实现了抽象工厂角色的方法。详细工厂角色含有与应用密切相关的逻辑。负责创建相应的详细的产品,与详细产品
角色一一相应
(3)抽象产品角色(BaseProduct):工厂方法模式所创建的全部产品的超类型,也就是全部产品类的共同拥有父类或者共同接口。
(4)详细产品角色(Product_A):继承或实现抽象产品角色。
client通过声明抽象工厂类对象。可获取到抽象工厂类对象的子类工厂,通过子类工厂创建产品的方法(显示返回抽象产品。实际返回详细产品)得到详细产品
类。当我们的系统中须要新增一种产品的时候,那我们不用改动原来的代码。仅仅须要在系统中添加一个详细工厂类和一个与之相相应的详细产品类就可以。
3、使用JAVA接口或者JAVA抽象类
我们也看到了,上面的抽象工厂类和抽象产品类我都是使用JAVA抽象类来实现的。实际中我们怎么选择呢。
假设详细工厂角色具有共同的逻辑。那么共同的逻辑就能够向上移动到抽象工厂角色中。这也就意味着抽象工厂角色应当由一个JAVA类实现,而且抽象工厂角色提
供默认的工厂方法。这个时候使用JAVA接口就不太合适,由于JAVA接口只描写叙述了方法的特征,而抽象类是能够描写叙述出方法的详细逻辑实现的。
事实上上面那个用例图没有必要用JAVA抽象类,由于他没有什么共同拥有逻辑须要在父类中实现。
对于没有共同拥有逻辑须要在父类中描写叙述的。那么使用JAVA接口好一些,由于我们JAVA语言是一种单继承语言。它仅仅能继承一个父类,所以使用继承的时候要谨慎,
而JAVA接口没这个限制,一个类能够实现多个接口(这也是为什么已经有了抽象类的概念,还要弄出个接口概念的原因)。
实际使用中这个问题还是须要我们针对系统的实际情况细致考虑一下的。
4、多态性的丧失和模式的退化
一个工厂方法模式的实现依赖于工厂角色和产品角色的多态性。在有些情况下,这个模式能够出现退化,其特点就是多态性的丧失。
工厂方法返还的应该是抽象类型而不是详细类型,仅仅有这样才干保证针对产品的多态性。
换言之,调用工厂方法的client总能够针对抽象编程,依赖于一个产品的抽象类型
而不是详细类型。
在特殊情况下,工厂方法仅返回一个详细产品类型,这个时候工厂方法就退化了,表现为针对产品角色的多态性的丧失。换言之。client知道了从工厂方法中获取的对象是
什么类型,这违背了工厂方法模式设计的原意,也就不是工厂方法模式了。
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 <tt>Iterator</tt> over the elements in this collection
*/
Iterator<E> 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<E> iterator();接下来再看ArrayList中的代码:
/**
* Returns an iterator over the elements in this list in proper sequence.
*
* <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
*
* @return an iterator over the elements in this list in proper sequence
*/
public Iterator<E> iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
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<E> {
/**
* 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源代码的内容,满足了开-闭原则。