工厂方法
定义
创建一个对象的接口(抽象类),但是让实现(继承)这个接口(抽象类)的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。
类型
创建型
适用场景
- 创建对象需要大量的重复代码
- 客户端(应用层)不依赖于产品实例如何被创建,实现等细节。
- 一个类通过其子类来指定创建哪个对象。
创建对象会产生大量的重复代码,工厂方法通过创建一个方法来交由子类创建对象。
工厂方法-优点
- 用户只需要关心产品对应的工厂,无需关心创建细节
- 加入新的产品符合开闭原则,提高可拓展性
工厂方法-缺点
- 类的个数过多,增加复杂度
- 增加了系统的抽象性和理解难度 下面我们开始coding,场景我们依然使用上节中的简单工厂场景
首先我们常见一个抽象类使用接口也是可以的。抽象类的作用是创建约束。
public abstract class Video {
public abstract void produce();
}
同样的我们再创建一个抽象类
public abstract class VideoFactory {
public abstract Video getVideo();
}
我们的javavideo类,javaVideo类继承抽象Video
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("录制Java课程视频");
}
}
javaVideo的工厂类,继承工厂类。我们的javaVideo的创建就是由这个类来完成。
public class JavaVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
}
假设我们还有个python课和前端课程,我们同样的方式创建这些类
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("录制Python课程视频");
}
}
public class PythonVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
}
public class FEVideo extends Video{
@Override
public void produce() {
System.out.println("录制FE课程视频");
}
}
public class FEVideoFactory extends VideoFactory{
@Override
public Video getVideo() {
return new FEVideo();
}
}
此时我们应用层的test类就应该这么写
public class MethodTest {
public static void main(String[] args) {
VideoFactory videoFactory = new PythonVideoFactory();
VideoFactory videoFactory2 = new JavaVideoFactory();
VideoFactory videoFactory3 = new FEVideoFactory();
Video video = videoFactory.getVideo();
video.produce();
}
}
最后我们来看一下这些类的uml图
从图中我们可以清晰的看出这些类之间的依赖关系,同时工厂方法类过多的缺点也展示出来了。
下面我们一起来看一下在jdk中有些类使用工厂方法的这个设计模式吧。 比如这个Iterable 接口中的iterator方法就是一个工厂方法,我们使用idea按住ctrl+鼠标左键查看他的实现。
.......
/**
* 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();
......
如图
我们就查看一下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();
}
这里使用一个内部类Itr来实现这个工厂方法。 从工厂方法的角度去看这个类的话,我们可以认为ArrayList就是一个具体实现工厂,Iterator接口就是抽象产品,而具体生产出来的产品就是Itr对象了。对比我们的Collection接口就相当于我们的VideoFactory类,而ArrayList就相当我们代码中的javaFactory等具体工厂实现。Iterator就想相当于我们代码中的抽象产品Video, itr是具体产品就相当于我们代码中的javaVideo等具体产品。
工厂方法模式今天就聊到这里。