设计模式 | 工厂方法及相关应用

工厂方法(Factory Method)

定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行

适用场景:

  • 创建对象需要大量重复的代码
  • 客户端不依赖于产品类示例如何被创建、实现等细节
  • 一个类通过其子类来指定创建哪个对象

优缺点

优点:用户只需要关心所需产品对应的工厂,无需关心创建细节;加入新产品符合开闭原则,提高可扩展性。

缺点:类的个数容易过多,增加复杂度。

应用场景

设计模式 | 工厂方法及相关应用

抽象产品类Video

public abstract class Video {
    public abstract void produce();

}

具体产品类JavaVideoPythonVideo

public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("录制Java课程视频");
    }
}

public class PythonVideo extends Video {
    @Override
    public void produce() {
        System.out.println("录制Python课程视频");
    }
}

抽象工厂类VideoFactory

public abstract class VideoFactory {
    public abstract Video getVideo();
}

具体工厂类JavaVideoFactoryPythonVideo

public class JavaVideoFactory extends VideoFactory {
    @Override
    public Video getVideo() {
        return new JavaVideo();
    }
}

public class PythonVideoFactory extends VideoFactory {
    @Override
    public Video getVideo() {
        return new PythonVideo();
    }
}

客户端类Test

public class Test {
    public static void main(String[] args) {
        VideoFactory videoFactory = new PythonVideoFactory();
        VideoFactory videoFactory2 = new JavaVideoFactory();
        Video video = videoFactory.getVideo();
        video.produce();
    }
}

设计模式 | 工厂方法及相关应用

这时如果需要增加一个新的产品时,只需要添加一个新的具体产品类和具体工厂类,而无需像简单工厂一样修改工厂类里面的判断逻辑,即满足了开闭原则。

例如,如果要增加新产品FEVideo,我们需要先加入一个具体产品类:

public class FEVideoFactory extends VideoFactory{
    @Override
    public Video getVideo() {
        return new FEVideo();
    }
}

再增加这个具体产品所对应的具体工厂类:

public class FEVideoFactory extends VideoFactory{
    @Override
    public Video getVideo() {
        return new FEVideo();
    }
}

之后在应用层就可以直接使用了:

public class Test {
    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类图:

设计模式 | 工厂方法及相关应用

Java集合接口Collection中的应用

java.util.Collection接口下的iterator()方法:

public interface Collection<E> extends Iterable<E> {
	//...
    Iterator<E> iterator();
    //...

查看该接口的其中一个实现类ArrayList

    public Iterator<E> iterator() {
        return new Itr();
    }
    
    private class Itr implements Iterator<E> {
		//...
        public boolean hasNext() {
            return cursor != size;
        }
        @SuppressWarnings("unchecked")
        public E next() {
			//...
        }
        public void remove() {
	        //...
        }
        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            //...
        }
        //...
    }

在这里,Collection相当于一个抽象工厂,而ArrayList相当于一个具体工厂,这个具体工厂实现了工厂方法iterator()实例化具体产品Itr,而这个具体产品实现了抽象产品Iterator

logback中的应用

设计模式 | 工厂方法及相关应用

由UML可以看出ILoggerFactory作为抽象的工厂类,实现有三个具体的工厂类,以其中的NOPLoggerFactory为例,实现了抽象方法getLogger来实例化具体产品类:

public class NOPLoggerFactory implements ILoggerFactory {
    public NOPLoggerFactory() {
    }

    public Logger getLogger(String name) {
        return NOPLogger.NOP_LOGGER;
    }
}