2.工厂方法
2.1 概述
定义:定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类工厂方法让类的实例化推迟到子类中进行。
类型:创建型
适用场景:
- 创建对象需要大量重复的代码
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 一个类通过其子类来指定创建哪个对象
优点:
- 用户只需关心所需产品对应的工厂,无需关心创建的细节
- 加入新的产品符合开闭原则,提高可扩展性
缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
2.2 代码理解
场景:
教学网站有不同种类的教学视频,Java、Python等,想新增什么教学视频时,从把想要的类型传 给 视频工厂,然后生产出视频。
Video
视频基类:
package com.gangbb.creational.factorymethod;
/**
* @author Gangbb
* @date 2021/3/27 20:44
*/
public abstract class Video {
/**
* 生产视频
*/
public abstract void produce();
}
JavaVideo
Java视频类:
package com.gangbb.creational.factorymethod;
/**
* @author Gangbb
* @date 2021/3/27 20:45
*/
public class JavaVideo extends Video {
/**
* 生产java视频
*/
public void produce() {
System.out.println("创建Java视频");
}
}
PythonVideo
Python视频类:
package com.gangbb.creational.factorymethod;
/**
* @author Gangbb
* @date 2021/3/27 20:46
*/
public class PythonVideo extends Video {
/**
* 生产python视频
*/
public void produce() {
System.out.println("生产python视频");
}
}
VideoFactory
视频工厂方法类:
package com.gangbb.creational.factorymethod;
/**
* @author Gangbb
* @date 2021/3/27 20:49
* @Description: 视频工厂方法类
*/
public abstract class VideoFactory {
public abstract Video getVideo();
}
PS:这里抽象类也可以定义成 接口
VideoFactory
只定义创建视频的契约和规范。具体创建什么视频创建,和创建的逻辑是由VideoFactory
的子类决定的。
子类JavaVideoFactory
:
package com.gangbb.creational.factorymethod;
/**
* @author Gangbb
* @date 2021/3/28 11:18
* @Description: Java视频工厂类
*/
public class JavaVideoFactory extends VideoFactory{
public Video getVideo() {
return new JavaVideo();
}
}
子类PythonVideoFactory
package com.gangbb.creational.factorymethod;
/**
* @author Gangbb
* @date 2021/3/28 11:27
* @Description: Python视频工厂
*/
public class PythonVideoFactory extends VideoFactory{
public Video getVideo() {
return new PythonVideo();
}
}
应用层调用:
Client
:
package com.gangbb.creational.factorymethod;
/**
* @author Gangbb
* @date 2021/3/27 20:47
* @Description: 模拟客户端类
*/
public class Client {
public static void main(String[] args) {
// 父类声明的引用指向子类的实现。 videoFactory为Java视频工厂
VideoFactory videoFactory = new JavaVideoFactory();
// 获得video
Video video = videoFactory.getVideo();
//生产video
video.produce();
}
}
此时类图
:
分析:
如果此时还要加入别的类型的课程。只需在创建XxxVideo
和XxxVideoFactory
类即可,不需要修改已有的类,大大降低业务出现风险的可能性。
2.3 开源框架源码使用分析
2.3.1 Java集合中的工厂方法体现
java.util.Collection
中的iterator
方法。
iterator
就是一个工厂方法,有很多实现类
它的子类定义了实现的逻辑。
例如ArrayList
也是他的实现类。
此时
抽象产品–Iterator
(相当于我们代码例子中的Video)
具体产品–ArrayList
中的Itr
类(相当于我们代码例子中的JavaVideo和PythonVideo)
工厂方法类–Collection
(相当于我们代码例子中的VideoFactory)
实现工厂–ArrayList
(相当于我们代码例子中的JavaVideoFactory和PythonVideoFactory)
2.3.2 JDK中解决url协议扩展的接口
java.net.URLStreamHandlerFactory
createURLStreamHandler
方法中的参数protocol
决定了交互的规范。
URLStreamHandlerFactory
的实现类Launcher
中的Factory
里面有一个返回值为URLStreamHandler
的createURLStreamHandler
方法。
URLStreamHandler
是一个抽象类,并且有各种协议的实现子类
随机看一个https协议实现类:
这是一个间接继承,最终也还是继承URLStreamHandler
此时
抽象产品–URLStreamHandler
(相当于我们代码例子中的Video)
具体产品–各种实现URLStreamHandler
的Handler
类(相当于我们代码例子中的JavaVideo和PythonVideo)
工厂方法类–URLStreamHandlerFactory
(相当于我们代码例子中的VideoFactory)
实现工厂–Launcher
中的Factory
(相当于我们代码例子中的JavaVideoFactory和PythonVideoFactory)
2.4 趣味理解
追 MM 少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是 MM 爱吃的东西,虽然口味有所不同,但不管你带 MM 去麦当劳或肯德基,只管向服务员说「来四个鸡翅」就行了。麦当劳和肯德基就是生产鸡翅的 Factory 工厂模式:客户类和工厂类分开。
消费者任何时候需要某种产品,只需向工厂请求即可。消费者无须修改就可以接纳新产品。缺点是当产品修改时,工厂类也要做相应的修改。如:如何创建及如何向客户端提供。