1 简单工厂模式 举个栗子🌰 我们根据配置文件的后缀(json、xml、yaml、properties),选择不同的解析器(JsonRuleConfigParser、XmlRuleConfigParser……),将存储在文件中的配置解析成内存对象 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 = "" ; RuleConfig ruleConfig = parser.parse(configText); return ruleConfig; } private String getFileExtension (String filePath) { 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 = "" ; RuleConfig ruleConfig = parser.parse(configText); return ruleConfig; } private String getFileExtension (String filePath) { 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 中的 DateFormat、Calender。 除此之外,工厂类中创建对象的方法一般都是 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 ; } 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(); } }
这样当我们新增一种 parser 的时候,只需要新增一个实现了 IRuleConfigParserFactory 接口的 Factory 类即可。 所以,工厂方法模式比起简单工厂模式更加符合开闭原则。
可以仿照 LayoutInflater 中 createService 逻辑实现复用。先调用 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 = "" ; RuleConfig ruleConfig = parser.parse(configText); return ruleConfig; } private String getFileExtension (String filePath) { 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 中即可。代码的改动非常少,基本上符合开闭原则。
我们还可以用反射来创建具体工厂,这样就不需要那么多工厂类,传入相应的 JsonRuleConfigParser 或 XmlRuleConfigParser 就可以。
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 为我们提供的 SharedPreferences 和 SQLite ,也可以使用常规的文件存储,但是,对数据操作的方法无非就是增、删、改、查,我们可以将每一种数据操作的方式作为一个产品类,在抽象产品类中定义操作的方法:
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 { 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 系统配置)来分类,那就会对应下面这 8 个 parser 类。
1 2 3 4 5 6 7 8 9 10 11 针对规则配置的解析器:基于接口IRuleConfigParser JsonRuleConfigParser XmlRuleConfigParser YamlRuleConfigParser PropertiesRuleConfigParser 针对系统配置的解析器:基于接口ISystemConfigParser JsonSystemConfigParser XmlSystemConfigParser YamlSystemConfigParser PropertiesSystemConfigParser
如果还是继续用工厂方法来实现的话,我们要针对每个 parser 都编写一个工厂类,也就是要编写 8 个工厂类。
抽象工厂就是针对这种非常特殊的场景而诞生的。我们可以让一个工厂负责创建多个不同类型的对象(IRuleConfigParser、ISystemConfigParser 等),而不是只创建一种 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 () ; } 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(); } }
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 源码的工厂模式 其实平时工作中也偷偷使用着工厂方法模式。以 List 和 Set 为例,List 和 Set 都继承于 Collection 接口,而 Collection 接口继承于 Iterable 接口,Iterable 接口很简单,就一个 iterator 方法:
1 2 3 public interface Iterable <T > { Iterator<T> iterator () ; }
这意味着 List 和 Set 接口也会继承该方法,平时比较常用的两个间接实现类 ArrayList 和 HashSet 中 iterator 方法的实现就是构造并返回一个迭代器对象:
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; int lastRet = -1 ; 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) { } } }
HashSet 的 iterator 方法中会返回成员变量 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(); } } }
ArrayList 和 HashSet 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 源码设计模式解析与实战》
以及上文中的链接