# 迭代器模式Iterator
# 一、概念
# 1、定义
定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行.
# 2、类型
创建型
# 3、适用场景
- 创建对象需要大量重复的代码
- 客户端(应用层)不依赖于产品类实现如何被创建、实现等细节
- 一个类通过其子类来制定创建哪个对象
# 4、优点
- 用户只需要关心所需产品对应的工厂,无序关心创建细节
- 加入新产品符合开闭原则,提高可扩展性
# 5、缺点
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
# 二、应用
继续接着上一篇博客 简单工厂SimpleFactory 讲,英雄类还是那个英雄类,力量英雄和敏捷英雄的类也不变,这里就不重复写了。
这时,创建视频的工厂要变化了,变为了一个抽象类:
public abstract class VideoFactory {
public abstract Video getVideo();
}
2
3
4
创建视频的方法已经不在主工厂中进行了,移交到了子类中。
新建一个专门用于创建Java视频的工厂:
public class JavaVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
}
2
3
4
5
6
7
同理,创建一个专门用于创建Python视频的工厂:
public class PythonVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
}
2
3
4
5
6
7
这样一来,应用层就这样子调用了:
public class Test {
public static void main(String[] args) {
VideoFactory videoFactory = new PythonVideoFactory();
VideoFactory videoFactory2 = new JavaVideoFactory();
Video video = videoFactory.getVideo();
video.produce();
}
}
2
3
4
5
6
7
8
9
运行结果:
录制Python课程视频
如果后续有新的类型的视频需要创建,并不需要修改 VideoFactory
类了,只需要重新创建一个新类型视频以及创建新类型视频的工厂,然后在应用层 new
出来这个新英雄工厂,并调用它的 getVideo()
方法就可以创建新的视频了。
例如添加一个新的前端视频:
public class FrontEndVideo extends Video {
@Override
public void produce() {
System.out.println("录制FrontEnd课程视频");
}
}
2
3
4
5
6
7
再来一个创建前端视频的工厂:
public class FrontEndVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new FrontEndVideo();
}
}
2
3
4
5
6
7
应用层代码:
public static void main(String[] args) {
VideoFactory videoFactory = new PythonVideoFactory();
VideoFactory videoFactory2 = new JavaVideoFactory();
VideoFactory videoFactory3 = new FrontEndVideoFactory();
Video video = videoFactory.getVideo();
video.produce();
Video frontEndVideo = videoFactory3.getVideo();
frontEndVideo.produce();
}
2
3
4
5
6
7
8
9
完全不用修改 VideoFactory
类了。
执行结果:
录制Python课程视频
录制FrontEnd课程视频
2
此时的类图:
VideoFactory
将创建具体某个视频的职责交由子类工厂实现,应用层也只用创建出来具体的子类工厂,然后从子类工厂中创建视频。
这里需要明确个概念:
Java视频、Python视频都是一个产品等级,它们都同属于“视频”这个产品的等级,它们都是产品。工厂方法是用来解决同一产品等级的问题的。
# 三、源码中的应用
# 1、Collection
Collection
可以理解是一个抽象工厂,类中的 Iterator<E> iterator()
方法就是一个工厂方法。其中 ArrayList
对它进行了实现:
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();
}
}
@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();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
ArrayList
相当于一个具体工厂,Iterator
相当于抽象产品,Itr
就是具体的产品。
ArrayList
相关的类图:
# 2、URLStreamHandlerFactory
URLStreamHandlerFactory
是一个接口,它是解决在 jdk
中协议扩展使用到的接口:
public interface URLStreamHandlerFactory {
/**
* Creates a new {@code URLStreamHandler} instance with the specified
* protocol.
*
* @param protocol the protocol ("{@code ftp}",
* "{@code http}", "{@code nntp}", etc.).
* @return a {@code URLStreamHandler} for the specific protocol.
* @see java.net.URLStreamHandler
*/
URLStreamHandler createURLStreamHandler(String protocol);
}
2
3
4
5
6
7
8
9
10
11
12
URLStreamHandlerFactory
就是一个抽象工厂,URLStreamHandler createURLStreeamHandler(String protocal)
就是一个工厂方法。有一个 Launcher
类的的内部类 Factory
实现了这个接口:
private static class Factory implements URLStreamHandlerFactory {
private static String PREFIX = "sun.net.www.protocol";
private Factory() {
}
public URLStreamHandler createURLStreamHandler(String var1) {
String var2 = PREFIX + "." + var1 + ".Handler";
try {
Class var3 = Class.forName(var2);
return (URLStreamHandler)var3.newInstance();
} catch (ReflectiveOperationException var4) {
throw new InternalError("could not load " + var1 + "system protocol handler", var4);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
这个 Factory
就是一个具体工厂。URLStreamHandler
就相当于抽象产品,sun.net.www.protocol.http
包下的 Handler
就是对抽象类 URLStreamHandler
的实现:
public class Handler extends URLStreamHandler {
protected String proxy;
protected int proxyPort;
protected int getDefaultPort() {
return 80;
}
public Handler() {
this.proxy = null;
this.proxyPort = -1;
}
public Handler(String var1, int var2) {
this.proxy = var1;
this.proxyPort = var2;
}
protected URLConnection openConnection(URL var1) throws IOException {
return this.openConnection(var1, (Proxy)null);
}
protected URLConnection openConnection(URL var1, Proxy var2) throws IOException {
return new HttpURLConnection(var1, var2, this);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
这个 Handler
就是一个具体产品。
# 3、ILoggerFactory
ILoggerFactory
也是一个工厂方法
public interface ILoggerFactory {
/**
* Return an appropriate {@link Logger} instance as specified by the
* <code>name</code> parameter.
*
* <p>If the name parameter is equal to {@link Logger#ROOT_LOGGER_NAME}, that is
* the string value "ROOT" (case insensitive), then the root logger of the
* underlying logging system is returned.
*
* <p>Null-valued name arguments are considered invalid.
*
* <p>Certain extremely simple logging systems, e.g. NOP, may always
* return the same logger instance regardless of the requested name.
*
* @param name the name of the Logger to return
* @return a Logger instance
*/
public Logger getLogger(String name);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
这个 getLogger()
方法就是一个工厂方法。
它的相关类图:
可以看出,具体的工厂有3个:NOPLoggerFactory
、LoggerContext
和 SubstituteLoggerFactory
。