工厂方法模式是定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。属于创建型,也属于GOF23种设计模式。
适用范围
- 1.创建对象需要大量重复的代码。
- 2.客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
- 3.一个类通过其子类来指定创建哪个对象。
优缺点
优点:用户只需要关心所需产品对应的工厂,无需关心创建细节。加入新产品符合开闭原则,提高可扩展性。
缺点:类的个人容易过多,增加复杂度。增加了系统的抽象性和理解难度。
示例
Video.java
视频抽象类,提供生产视频的抽象方法。
package com.zaiae.design.pattern.creational.factorymethod;
public abstract class Video {
public abstract void produce();
}
JavaVideo.java
Java视频类,继承视频抽象类,并实现自己的生产视频逻辑。
package com.zaiae.design.pattern.creational.factorymethod;
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("录制一套Java课程视频");
}
}
PythonVideo.java
Python视频类,继承视频抽象类,并实现自己的生产视频逻辑。
package com.zaiae.design.pattern.creational.factorymethod;
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("录制一套Python课程视频");
}
}
VideoFactory.java
生产视频的工厂方法基类,只定义规范和契约。我们该使用抽象类还是接口,需要根据实际需求来确定。
package com.zaiae.design.pattern.creational.factorymethod;
public abstract class VideoFactory {
public abstract Video getVideo();
}
JavaVideoFactory.java
生产Java视频的工厂方法类,创建需要的对象。
package com.zaiae.design.pattern.creational.factorymethod;
public class JavaVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
}
PythonVideoFactory.java
生产Python视频的工厂方法类,创建需要的对象。
package com.zaiae.design.pattern.creational.factorymethod;
public class PythonVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
}
Test.java
客户端(应用层)调用工厂方法,创建需要的对象。
package com.zaiae.design.pattern.creational.factorymethod;
public class Test {
public static void main(String[] args) {
VideoFactory videoFactory = new JavaVideoFactory();
videoFactory.getVideo().produce();
VideoFactory videoFactory1 = new PythonVideoFactory();
videoFactory1.getVideo().produce();
}
}
UML结构图:
JDK中的使用例子
例如在 java.util.Collection
接口中的 Iterator<E> iterator()
方法,就是一个工厂方法。
在具体的实现工厂 java.util.ArrayList
中重写 Iterator<E> iterator()
方法,用于创建 Iterator
实例对象。
public Iterator<E> iterator() {
return new 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();
}
}