工厂模式

简单工厂(Simple Factory)

假设有这样一个场景,我们要根据url进行资源的加载,如果我们把所有的加载实现都写在同一个load方法中,那么方法就会非常的长,而且拓展性很差

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class ResourceLoader {
public Resource load(String filePath) {
String prefix = getResourcePrefix(filePath);
Resource resource = null;
if ("http".equals(type)) {
// ..发起请求下载资源... 可能很复杂
return new Resource(url);
} else if ("file".equals(type)) {
// ..建立流,做异常处理等等
return new Resource(url);
} else if ("classpath".equals(type)) {
// ...
return new Resource(url);
} else {
return new Resource("default");
}
return resource;
}

private String getPrefix(String url) {
if (url == null || "".equals(url) || !url.contains(":")) {
throw new ResourceLoadException("此资源url不合法.");
}
String[] split = url.split(":");
return split[0];
}
}

上面有很多if-else,导致难以拓展,我们可以看到,全部分支的逻辑就是创建一个资源,所以我们只需要一个工厂类,把创建资源的能力交给工厂就可以了

这样做的好处

  1. 工厂将创建的过程进行封装,不需要关系创建的细节,更加符合面向对象思想
  2. 这样主要的业务逻辑不会被创建对象的代码干扰,代码更易阅读
  3. 产品的创建可以独立测试,更将容易测试
  4. 独立的工厂类只负责创建产品,更加符合单一原则

工厂方法(Factory Method)

随着需求的变多,if-else分支不断膨胀,这时候我们就有必要把if-else去掉,经典的方法就是利用多态,为每个资源创建一个独立的工厂类,他们都继承一个工厂父类,然后利用缓存把方法名和工厂对象存起来,在使用的时候就可以根据名字直接调用。上面的简单工厂是一个工厂负责生产全部产品,现在是一个工厂生产一个产品。

1
2
3
4
5
6
7
8
9
private static Map resourceLoaderCache = new HashMap<>(8);

// 版本二
static {
resourceLoaderCache.put("http", new HttpResourceLoader());
resourceLoaderCache.put("file", new FileResourceLoader());
resourceLoaderCache.put("classpath", new ClassPathResourceLoader());
resourceLoaderCache.put("default", new DefaultResourceLoader());
}

获取资源的方法就可以是

1
2
3
4
5
public Resource load(String url) {
// 1、根据url获取前缀
String prefix = getPrefix(url);
return resourceLoaderCache.get(prefix).load(url);
}

抽象工厂(Abstract Factory)

抽象工厂解决的是多业务品种,业务分类的问题。简单来说就是把同一类的东西聚合在一起,然后提供一个抽象的方法去创建对象

应用场景

当创建逻辑比较复杂,是一个“大工程”的时候,我们就应该考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用相分离

第一种情况:类似规则配置解析的例子,代码中存在 if-else 分支判断,动态地根据不同的类型创建不同的对象。针对这种情况,我们就考虑使用工厂模式,将这一大坨 if-else 创建对象的代码抽离出来,放到工厂类中。

还有一种情况,尽管我们不需要根据不同的类型创建不同的对象,但是,单个对象本身的**创建过程比较复杂,**比如前面提到的要组合其他类对象,做各种初始化操作。在这种情况下,我们也可以考虑使用工厂模式,将对象的创建过程封装到工厂类中