# 简单工厂
关联阅读 李兴华-简单工厂
定义:由一个工厂对象决定创建出哪一种产品类的实例
类型:创建型,但不属于 GOF23 种设计模式
抽象工厂和工厂方法模式是由简单工厂一步一步进化的
# 适用场景
- 工厂类负责创建的对象比较少
- 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心
# 优点
- 只需要传入一个正确的参数,就可以获取你所需要的对象
- 无须知道其创建细节
# 缺点
职责相对过重
增加新的产品,需要修改工厂类的判断逻辑,违背开闭原则
# coding
维基百科: https://en.wikipedia.org/wiki/Design_Patterns#Patterns_by_Type
Creational 中是没有简单工厂模式的。所以不属于 GOF23 种设计模式
场景:生成课程视频,不同的课程生成的视频逻辑不一样
# 不用模式
public abstract class Video {
public abstract void produce();
}
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 课程");
}
}
public class Test {
public static void main(String[] args) {
Video video = new JavaVideo();
video.produce();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
目前这个客户端(Test)需要依赖具体的实现类,那么能否让应用层不依赖具体的实现类呢?(很多时候基本上不会去用子类的特有方法)
# 使用简单工厂改造
public class VideoFactory {
public Video getVideo(String type) {
if ("java".equalsIgnoreCase(type)) {
return new JavaVideo();
} else if ("python".equalsIgnoreCase(type)) {
return new PythonVideo();
}
return null;
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
客户端则不需要依赖具体的实现类,直接和简单工厂交互,得到 Video 实例即可
public class Test {
public static void main(String[] args) {
// Video video = new JavaVideo();
// video.produce();
VideoFactory factory = new VideoFactory();
Video video = factory.getVideo("java");
video.produce();
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
新增课程的时候,还是需要修改工厂类的判定。我们追求的是对扩展开放,对修改关闭,那么就可以使用工厂方法来演进一下,到时候再对比下简单工厂
这里还可以使用反射里弥补下简单工厂的扩展性
# 使用反射演进简单工厂
public class VideoFactory {
public Video getVideo(Class c) {
String name = c.getName();
Video video = null;
try {
video = (Video) Class.forName(name).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return video;
}
}
public class Test {
public static void main(String[] args) {
VideoFactory factory = new VideoFactory();
Video video = factory.getVideo(JavaVideo.class);
video.produce();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
这个改进在一定成都上满足了开闭原则,对于新增课程,工厂类不需要修改,但是 客户端又依赖了具体的实现类。
所以说,设计模式和设计原则只能是适度,并且结合当前的业务模型,做一个权衡的取舍,没有固定的好方式
# jdk 中部分类使用简单工厂的源码
java.util.Calendar
Calendar.getInstance() 获取日历对象的实例就是一个简单工厂
public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
CalendarProvider provider =
LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
.getCalendarProvider();
if (provider != null) {
try {
// 提供者,根据传入的时区和 地区 获取实例,这就是一个简单工厂的例子
return provider.getInstance(zone, aLocale);
} catch (IllegalArgumentException iae) {
// fall back to the default instantiation
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
这里记录下,在idea中怎么看uml类图,之前是不会看
上图打开之后,默认只会显示 这一个类的父类,子类怎么显示呢?
# 日志框架
org.slf4j.LoggerFactory#getLogger(java.lang.Class<?>)
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
// 也是根据名称返回实例
return iLoggerFactory.getLogger(name);
}
1
2
3
4
5
6
7
2
3
4
5
6
7
# 源码的阅读
- 可以通过上面类图的查看方式,了解一些主要类的情况
- 可以通过设计模式来聚焦理解