1 简单工厂模式

举个栗子🌰 我们根据配置文件的后缀(jsonxmlyamlproperties),选择不同的解析器(JsonRuleConfigParserXmlRuleConfigParser……),将存储在文件中的配置解析成内存对象 RuleConfig

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
28
public class RuleConfigSource {
public RuleConfig load(String ruleConfigFilePath) {
String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);
IRuleConfigParser parser = null;
if ("json".equalsIgnoreCase(ruleConfigFileExtension)) {
parser = new JsonRuleConfigParser();
} else if ("xml".equalsIgnoreCase(ruleConfigFileExtension)) {
parser = new XmlRuleConfigParser();
} else if ("yaml".equalsIgnoreCase(ruleConfigFileExtension)) {
parser = new YamlRuleConfigParser();
} else if ("properties".equalsIgnoreCase(ruleConfigFileExtension)) {
parser = new PropertiesRuleConfigParser();
} else {
throw new InvalidRuleConfigException(
"Rule config file format is not supported: " + ruleConfigFilePath);
}

String configText = "";
//从ruleConfigFilePath文件中读取配置文本到configText中
RuleConfig ruleConfig = parser.parse(configText);
return ruleConfig;
}

private String getFileExtension(String filePath) {
//...解析文件名获取扩展名,比如rule.json,返回json
return "json";
}
}

这块代码都耦合进了 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
28
29
30
31
32
33
34
35
public class RuleConfigSource {
public RuleConfig load(String ruleConfigFilePath) {
String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);
IRuleConfigParser parser = RuleConfigParserFactory.createParser(ruleConfigFileExtension);
if (parser == null) {
throw new InvalidRuleConfigException(
"Rule config file format is not supported: " + ruleConfigFilePath);
}
String configText = "";
//从ruleConfigFilePath文件中读取配置文本到configText中
RuleConfig ruleConfig = parser.parse(configText);
return ruleConfig;
}

private String getFileExtension(String filePath) {
//...解析文件名获取扩展名,比如rule.json,返回json
return "json";
}
}

public class RuleConfigParserFactory {
public static IRuleConfigParser createParser(String configFormat) {
IRuleConfigParser parser = null;
if ("json".equalsIgnoreCase(configFormat)) {
parser = new JsonRuleConfigParser();
} else if ("xml".equalsIgnoreCase(configFormat)) {
parser = new XmlRuleConfigParser();
} else if ("yaml".equalsIgnoreCase(configFormat)) {
parser = new YamlRuleConfigParser();
} else if ("properties".equalsIgnoreCase(configFormat)) {
parser = new PropertiesRuleConfigParser();
}
return parser;
}
}

大部分工厂类都是以 “Factory” 这个单词结尾的,但也不是必须的,比如 Java 中的 DateFormatCalender
除此之外,工厂类中创建对象的方法一般都是 create 开头,比如代码中的 createParser(),但有的也命名为 getInstance()createInstance()newInstance(),有的甚至命名为 valueOf()(比如 Java String 类的 valueOf() 函数)等等。

我们还可以将单例结合进来,像之前单例中讲的那样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class RuleConfigParserFactory {
private static final Map<String, RuleConfigParser> cachedParsers = new HashMap<>();

static {
cachedParsers.put("json", new JsonRuleConfigParser());
cachedParsers.put("xml", new XmlRuleConfigParser());
cachedParsers.put("yaml", new YamlRuleConfigParser());
cachedParsers.put("properties", new PropertiesRuleConfigParser());
}

public static IRuleConfigParser createParser(String configFormat) {
if (configFormat == null || configFormat.isEmpty()) {
return null;//返回null还是IllegalArgumentException全凭你自己说了算
}
IRuleConfigParser parser = cachedParsers.get(configFormat.toLowerCase());
return parser;
}
}

2 工厂方法

现在在初始化 RuleConfigParserFactory 的时候已经将所有的 Parser 对象都实例化了。我们可以利用多态,延迟初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface IRuleConfigParserFactory {
IRuleConfigParser createParser();
}

public class JsonRuleConfigParserFactory implements IRuleConfigParserFactory {
@Override
public IRuleConfigParser createParser() {
return new JsonRuleConfigParser();
}
}

public class XmlRuleConfigParserFactory implements IRuleConfigParserFactory {
@Override
public IRuleConfigParser createParser() {
return new XmlRuleConfigParser();
}
}

// 省略YamlConfigParserFactory和PropertiesConfigParserFactory代码

这样当我们新增一种 parser 的时候,只需要新增一个实现了 IRuleConfigParserFactory 接口的 Factory 类即可。
所以,工厂方法模式比起简单工厂模式更加符合开闭原则。

可以仿照 LayoutInflatercreateService 逻辑实现复用。先调用 getService 去获取有没有缓存,没有再 create

我们可以为工厂类再创建一个简单工厂,也就是工厂的工厂,用来创建工厂类对象。

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class RuleConfigSource {
public RuleConfig load(String ruleConfigFilePath) {
String ruleConfigFileExtension = getFileExtension(ruleConfigFilePath);

IRuleConfigParserFactory parserFactory = RuleConfigParserFactoryMap.getParserFactory(ruleConfigFileExtension);
if (parserFactory == null) {
throw new InvalidRuleConfigException("Rule config file format is not supported: " + ruleConfigFilePath);
}
IRuleConfigParser parser = parserFactory.createParser();

String configText = "";
//从ruleConfigFilePath文件中读取配置文本到configText中
RuleConfig ruleConfig = parser.parse(configText);
return ruleConfig;
}

private String getFileExtension(String filePath) {
//...解析文件名获取扩展名,比如rule.json,返回json
return "json";
}
}

//因为工厂类只包含方法,不包含成员变量,完全可以复用,
//不需要每次都创建新的工厂类对象,所以,简单工厂模式的第二种实现思路更加合适。
public class RuleConfigParserFactoryMap { //工厂的工厂
private static final Map<String, IRuleConfigParserFactory> cachedFactories = new HashMap<>();

static {
cachedFactories.put("json", new JsonRuleConfigParserFactory());
cachedFactories.put("xml", new XmlRuleConfigParserFactory());
cachedFactories.put("yaml", new YamlRuleConfigParserFactory());
cachedFactories.put("properties", new PropertiesRuleConfigParserFactory());
}

public static IRuleConfigParserFactory getParserFactory(String type) {
if (type == null || type.isEmpty()) {
return null;
}
IRuleConfigParserFactory parserFactory = cachedFactories.get(type.toLowerCase());
return parserFactory;
}
}

当我们需要添加新的规则配置解析器的时候,我们只需要创建新的 parser 类和 parser factory 类,并且在 RuleConfigParserFactoryMap 类中,将新的 parser factory 对象添加到 cachedFactories 中即可。代码的改动非常少,基本上符合开闭原则。

我们还可以用反射来创建具体工厂,这样就不需要那么多工厂类,传入相应的 JsonRuleConfigParserXmlRuleConfigParser 就可以。

1
2
3
4
5
6
7
8
9
10
public class RuleConfigParserFactory {
public <T extends IRuleConfigParser> T createParser(Class<T> clz){
IRuleConfigParser parser = null;
try {
parser = (IRuleConfigParser) Class.forName(clz.getName()).newInstance();
}catch (Exception e){
e.printStackTrace();
}
}
}

2.1 工厂方法 Android 实战

工厂方法模式比较简单,可以在很多编程实战的地方应用到它,以一个数据存储为例,大家知道 Android 数据持久化有很多种方式,可以使用 Android 为我们提供的 SharedPreferencesSQLite ,也可以使用常规的文件存储,但是,对数据操作的方法无非就是增、删、改、查,我们可以将每一种数据操作的方式作为一个产品类,在抽象产品类中定义操作的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public abstract class IOHandler {
/**
* 添加一条个人信息
* @param id 身份证号码
* @param name 名字
*/
public abstract void add(String id, String name);

/**
* 删除一条个人信息
*/
public abstract void remove(String id);

/**
* 更新一条个人信息
*/
public abstract void update(String id, String name);

/**
* 查询身份证对应的人名字
*/
public abstract String query(String id);
}

每一种持久化方式我们定义一个具体的 IO 处理类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FileHandler extends IOHandler {
@Override
public void add(String id, String name) {}

@Override
public void remove(String id) {}

@Override
public void update(String id, String name) {}

@Override
public String query(String id) {
return "file";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class XMLHandler extends IOHandler {
@Override
public void add(String id, String name) {}

@Override
public void remove(String id) {}

@Override
public void update(String id, String name) {}

@Override
public String query(String id) {
return "xml";
}
}

这里只是 query 做了区分。接下里是工厂类的定义,这里使用反射。

1
2
3
4
5
6
7
8
9
10
11
public class IOFactory {
public static <T extends IOHandler> T getIOHandler(Class<T> clz) {
IOHandler handler = null;
try {
handler = (IOHandler) Class.forName(clz.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return (T) handler;
}
}

最后的使用。

1
2
3
4
IOHandler handler = IOFactory.getIOHandler(FileHandler.class);
handler.query("handler");
IOHandler handler2 = IOFactory.getIOHandler(XMLHandler.class);
handler2.query("handler");

最后会输出不同的值。

3 抽象工厂

抽象工厂模式的应用场景比较特殊,没有前两种常用。

在简单工厂和工厂方法中,类只有一种分类方式。
比如,在规则配置解析那个例子中,解析器类只会根据配置文件格式(Json、Xml、Yaml……)来分类。
但是,如果类有两种分类方式,比如,我们既可以按照配置文件格式来分类,也可以按照解析的对象(Rule 规则配置还是 System 系统配置)来分类,那就会对应下面这 8parser 类。

1
2
3
4
5
6
7
8
9
10
11
针对规则配置的解析器:基于接口IRuleConfigParser
JsonRuleConfigParser
XmlRuleConfigParser
YamlRuleConfigParser
PropertiesRuleConfigParser

针对系统配置的解析器:基于接口ISystemConfigParser
JsonSystemConfigParser
XmlSystemConfigParser
YamlSystemConfigParser
PropertiesSystemConfigParser

如果还是继续用工厂方法来实现的话,我们要针对每个 parser 都编写一个工厂类,也就是要编写 8 个工厂类。

抽象工厂就是针对这种非常特殊的场景而诞生的。我们可以让一个工厂负责创建多个不同类型的对象(IRuleConfigParserISystemConfigParser 等),而不是只创建一种 parser 对象。这样就可以有效地减少工厂类的个数。

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
28
29
30
31
public interface IConfigParserFactory {
IRuleConfigParser createRuleParser();
ISystemConfigParser createSystemParser();
//此处可以扩展新的parser类型,比如IBizConfigParser
}

public class JsonConfigParserFactory implements IConfigParserFactory {
@Override
public IRuleConfigParser createRuleParser() {
return new JsonRuleConfigParser();
}

@Override
public ISystemConfigParser createSystemParser() {
return new JsonSystemConfigParser();
}
}

public class XmlConfigParserFactory implements IConfigParserFactory {
@Override
public IRuleConfigParser createRuleParser() {
return new XmlRuleConfigParser();
}

@Override
public ISystemConfigParser createSystemParser() {
return new XmlSystemConfigParser();
}
}

// 省略YamlConfigParserFactory和PropertiesConfigParserFactory代码

3.1 抽象工厂 Android 实战

这里模拟一个车场,分别生产 Q3 Q7是一个车系,但是零部件都不一样。

首先是轮胎部件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface ITire {
/**
* 轮胎
*/
void tire();
}

public class NormalTire implements ITire {
@Override
public void tire() {
LogUtils.i("普通轮胎");
}
}

public class SUVTire implements ITire {
@Override
public void tire() {
LogUtils.i("越野轮胎");
}
}

然后是发动机部件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface IEngine {
/**
* 发动机
*/
void engine();
}

public class DomesticEngine implements IEngine {
@Override
public void engine() {
LogUtils.i("国产发动机");
}
}

public class ImportEngine implements IEngine {
@Override
public void engine() {
LogUtils.i("进口发动机");
}
}

然后是制动系统。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public interface IBrake {
/**
* 制动系统
*/
void brake();
}

public class NormalBrake implements IBrake {
@Override
public void brake() {
LogUtils.i("普通制动");
}
}

public class SeniorBrake implements IBrake {
@Override
public void brake() {
LogUtils.i("高级制动");
}
}

最后是汽车制造工厂类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public abstract class CarFactory {
/**
* 生产轮胎
*/
public abstract ITire createTire();

/**
* 生产发动机
*/
public abstract IEngine createEngine();

/**
* 生产制动系统
*/
public abstract IBrake createBrake();
}

不同的车间生成不同的车,生产方式一样,但是部件不同。

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
28
29
30
31
32
33
34
35
36
public class Q3Factory extends CarFactory {

@Override
public ITire createTire() {
return new NormalTire();
}

@Override
public IEngine createEngine() {
return new DomesticEngine();
}

@Override
public IBrake createBrake() {
return new NormalBrake();
}
}

public class Q7Factory extends CarFactory {

@Override
public ITire createTire() {
return new SUVTire();
}

@Override
public IEngine createEngine() {
return new ImportEngine();
}

@Override
public IBrake createBrake() {
return new SeniorBrake();
}
}

1
2
3
4
CarFactory factoryQ3=new Q3Factory();
factoryQ3.createTire().tire();
factoryQ3.createEngine().engine();
factoryQ3.createBrake().brake();

6 Android 源码的工厂模式

其实平时工作中也偷偷使用着工厂方法模式。以 ListSet 为例,ListSet 都继承于 Collection 接口,而 Collection 接口继承于 Iterable 接口,Iterable 接口很简单,就一个 iterator 方法:

1
2
3
public interface Iterable<T> {
Iterator<T> iterator();
}

这意味着 ListSet 接口也会继承该方法,平时比较常用的两个间接实现类 ArrayListHashSetiterator 方法的实现就是构造并返回一个迭代器对象:

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
28
29
30
31
32
33
34
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
public Iterator<E> iterator() {
return new Itr();
}

private class Itr implements Iterator<E> {
protected int limit = ArrayList.this.size;

int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;

public boolean hasNext() {
return cursor < limit;
}

@SuppressWarnings("unchecked")
public E next() {
//...
}

public void remove() {
//...
}

@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
//...
}
}
}

HashSetiterator 方法中会返回成员变量 map 中对应 HashSet 对象元素的迭代器对象,最终返回的是 KeySet 中的一个迭代器对象:

1
2
3
4
5
6
7
8
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
public Iterator<E> iterator() {
return map.keySet().iterator();
}
}
1
2
3
4
5
6
7
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {

final class KeySet extends AbstractSet<K> {
public final Iterator<K> iterator() { return new KeyIterator(); }
}
}

ArrayListHashSet HashMap 中的 iterator 方法其实相当于一个工厂方法,专为 new 对象而生,这里 iterator 方法是构造并返回一个具体的迭代器。

1
2
3
4
5
6
7
public class MainActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
}
}

再仔细看 onCreate 方法,感觉也像一个工厂方法模式,因为我们每个 Activity 都会重新 onCreate 设置不同的布局,这不就是一个工厂模式的结构吗?

关于 onCreate startActivity启动过程分析

感谢

设计模式之美

《Android 源码设计模式解析与实战》

以及上文中的链接