定义:
定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,即让类的实例化推迟到子类中进行。
与简单工厂相比,工厂类不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式在添加新产品的时候就不修改工厂类逻辑而是添加新的工厂子类,符合开放封闭原则,克服了简单工厂模式中缺点。
类型:
创建型
适用场景:
- 创建对象需要大量重复的代码
- 客户端(应用层)不依赖于产品类实例如何被创建,实现等细节
- 一个类通过器子类来指定创建哪个对象
优点:
- 用户只需要关心所需要产品对应的工厂,无需关心创建细节
- 加入新产品符合开闭原则,提高可扩展性
缺点:
- 每增加一个产品,就需要增加一个产品类和产品工厂类,会造成类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
UML类图
- Abstract Factory:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 newProduct() 来创建产品。
- ConcreteFactory:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- Product:定义了产品的规范,描述了产品的主要特性和功能。
- ConcreteProduct:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
实例
还是以学习课程这个模型,上次已经使用简单工厂进行了抽象,现在采用工厂方法进行抽象;
还是以JavaCourse和PythonCourse
public interface Course {
void learn();
}
public class PythonCourse implements Course {
@Override
public void learn() {
System.out.println("学习Python");
}
}
public class JavaCourse implements Course {
@Override
public void learn() {
System.out.println("学习Java");
}
}
现在CourseFactory不在自己创建课程实例,而是交由实现它的各种课程工厂创建课程实例
public abstract class CourseFactory {
public abstract Course createCourse();
}
public class JavaCourseFactory extends CourseFactory{
@Override
public Course createCourse() {
return new JavaCourse();
}
}
public class PythonCourseFactory extends CourseFactory {
@Override
public Course createCourse() {
return new PythonCourse();
}
}
这里创建的方法不限于new,也通过其他方式,比如反射;
public static void main(String[] args) {
CourseFactory courseFactory = new PythonCourseFactory();
Course course = courseFactory.createCourse();
course.learn();
}
如果要学习JavaCourse,只需要在代码中将PythonCourse改成JavaCourse,在应用层上的修改很简单;
此外,如果要学习其他Course,只需要创建Course的实现类和与其对应的CourseFactory即可,有很高的扩展性。
工厂方法是解决相同产品等级的产品的问题。
相同产品等级:比如都是冰箱,但是它有不同的厂商;美的的冰箱,海尔的冰箱就是同一产品等级;在类图上反映就是在一个接口下同一行的实现类。
源码
- 在接口Collection中,有一个iterator的抽象方法,然后发现在Collection的实现类ArrayList中,iterator方法采用了工厂方法;
public interface Collection<E> extends Iterable<E> {
Iterator<E> iterator();
}
public class ArrayList<E> extends AbstractList<E>{
public Iterator<E> iterator() {
return new Itr();
}
private class Itr implements Iterator<E> {
...
}
...
}
Itr是ArrayList的内部类,它是Iterator的实现类;
在这里Collection是工厂,ArrayList是具体的工厂,Iterator是产品,而Itr是具体是产品。
- URLStreamHandlerFactory接口与其子类中也采用了工厂方法
public interface URLStreamHandlerFactory {
URLStreamHandler createURLStreamHandler(String protocol);
}
URLStreamHandlerFactory只有一个抽象方法,然后看下它的实现类
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);
}
}
}
这个类也是个内部类,它定义在Launcher类内;
能看到,createURLStreamHandler方法中采用的反射的方式创建对象;
public abstract class URLStreamHandler
并且URLStreamHandler是一个抽象类;
在这里,URLStreamHandlerFactory是工厂,Factory是具体的工厂,URLStreamHandler是产品,而其用反射创建的子类就是具体的产品。