定义与类型
定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。
类型:创建型
适用场景
- 创建对象需要大量重复代码
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 一个类通过其子类来制定创建哪个对象
优点
- 用户只需要关心所需产品对应的工厂,无须关心创建细节
- 加入新产品符合开闭原则,提高可扩展性
缺点
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
代码示例
以之前的简单工厂,不同的课程视频为例
- 创建VideoFactory类
/**
* @author lijiayin
*/
public abstract class VideoFactory {
public abstract Video getVideo();
}
- 创建Video类
/**
* @author lijiayin
*/
public abstract class Video {
public abstract void produce();
}
- 创建JavaVideo类
/**
* @author lijiayin
*/
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("Java");
}
}
- 创建PythonVideo类
/**
* @author lijiayin
*/
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("Python");
}
}
- 创建JavaVideoFactory类
/**
* @author lijiayin
*/
public class JavaVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
}
- 创建PythonVideoFactory类
/**
* @author lijiayin
*/
public class PythonVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
}
- 创建测试类
/**
* @author lijiayin
*/
public class Test {
public static void main(String[] args) {
VideoFactory videoFactory = new JavaVideoFactory();
Video video = videoFactory.getVideo();
video.produce();
VideoFactory videoFactory2 = new PythonVideoFactory();
Video video2 = videoFactory2.getVideo();
video2.produce();
}
}
-
测试结果
测试结果.png -
UML图
UML.png
JDK示例
- Collection接口,相当于VideoFactory抽象类,定义了Iterator<E> iterator()方法,相当于Video getVideo()方法;
public interface Collection<E> extends Iterable<E> {
......
Iterator<E> iterator();
......
}
- ArrayList类,相当于JavaVideoFactory类,实现了具体的iterator()方法;
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
......
public Iterator<E> iterator() {
return new Itr();
}
......
}
- Iterator接口,相当于Video抽象类,定义了需要实现的产品;
package java.util;
import java.util.function.Consumer;
/**
* An iterator over a collection. {@code Iterator} takes the place of
* {@link Enumeration} in the Java Collections Framework. Iterators
* differ from enumerations in two ways:
*
* <ul>
* <li> Iterators allow the caller to remove elements from the
* underlying collection during the iteration with well-defined
* semantics.
* <li> Method names have been improved.
* </ul>
*
* <p>This interface is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
* Java Collections Framework</a>.
*
* @param <E> the type of elements returned by this iterator
*
* @author Josh Bloch
* @see Collection
* @see ListIterator
* @see Iterable
* @since 1.2
*/
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.
*
* @implSpec
* The default implementation throws an instance of
* {@link UnsupportedOperationException} and performs no other action.
*
* @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
*/
default void remove() {
throw new UnsupportedOperationException("remove");
}
/**
* Performs the given action for each remaining element until all elements
* have been processed or the action throws an exception. Actions are
* performed in the order of iteration, if that order is specified.
* Exceptions thrown by the action are relayed to the caller.
*
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* while (hasNext())
* action.accept(next());
* }</pre>
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
* @since 1.8
*/
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
}
- ArrayList的内部类Itr,相当于JavaVideo类,具体实现了产品;
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
......
/**
* 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;
Itr() {}
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();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
......
}
网友评论