什么是工厂模式(Factory Design Pattern)?
前面讲述了单例模式,今天我们来看看创建型设计模式里的工厂模式。
工厂方法模式,是一种创建型设计模式, 其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。
在GoF设计模式中,将工厂模式分为工厂方法和抽象工厂,本文对工厂模式最进一步的划分,划分为简单工厂、工厂方法和抽象工厂。
什么是简单工厂?
什么是简单工厂,我们先看一下这个例子,示例代码如下:
public class ConvertService {
public <T> T convert(String data, Class<T> type) {
Convertor convertor = null;
if(int.class.equals(type)) {
convertor = new String2IntConvertor();
} else if(long.class.equals(type)) {
convertor = new String2LongConvertor();
} else if(...) {
...
} else {
throw new InvalidTypeException("Convertor is not supported: " + type);
}
return convertor.doConvert(data);
}
}
为了让代码可读性更好,更为清晰,我们将功能相对独立的部分抽取出来,示例代码如下:
public class ConvertService {
public <T> T convert(String data, Class<T> type) {
Convertor convertor = ConvertorFactory.createConvertor(type);
if(convertor == null) {
throw new InvalidTypeException("Convertor is not supported: " + type);
}
return convertor.doConvert(data);
}
}
public class ConvertorFactory {
public static Convertor createConvertor(Class<T> type) {
Convertor convertor = null;
if(int.class.equals(type)) {
convertor = new String2IntConvertor();
} else if(long.class.equals(type)) {
convertor = new String2LongConvertor();
} else if(...) {
...
}
return convertor;
}
}
工厂的命名一般以“Factory”结尾,但也不是必须的(e.g. Java 的 DateFormat、Calender)。工厂类创建对象一般以“create”开头,也不是肯定的(e.g. getInstance()、createInstance()、newInstance()、valueOf())。这些都可以根据具体场景和习惯命名即可。
上面的代码,如果 if-else 分支很长,将严重影响可读性,我们可以对上述代码进一步优化重构:
public class ConvertService {
public <T> T convert(String data, Class<T> type) {
Convertor convertor = ConvertorFactory.createConvertor(type);
if(convertor == null) {
throw new InvalidTypeException("Convertor is not supported: " + type);
}
return convertor.doConvert(data);
}
}
public class ConvertorFactory {
private static final Map<Class, Convertor> cachedConvertors = new HashMap<>();
static {
cachedConvertors.put(int.class, new String2IntConvertor());
cachedConvertors.put(long.class, new String2LongConvertor());
...
}
public static Convertor createConvertor(Class<T> type) {
return cachedConvertors.get(type);
}
}
上面代码实现了简单工厂模式,虽然提高了代码的扩展性,相比原来代码更符合开闭原则,但是同时也增加了类的个数,牺牲了部分代码的可读性。
虽然违背开闭原则,但是权衡扩展性和可读性,这样的实现写法在大多数情况下都是没问题的。
什么是工厂方法?
基于上面的例子,我们调整成工厂方法的形式,示例代码如下:
public class ConvertService {
public <T> T convert(String data, Class<T> type) {
ConvertorConcreteFactory factory = ConvertorFactory.createConvertor(type);
if(factory == null) {
throw new InvalidTypeException("Convertor is not supported: " + type);
}
Convertor convertor = factory.createConvertor();
return convertor.doConvert(data);
}
}
public class ConvertorFactory {
private static final Map<Class, ConvertorConcreteFactory> cachedConcreteFactories = new HashMap<>();
static {
cachedConcreteFactories.put(int.class, new String2IntConvertorConcreteFactory());
cachedConcreteFactories.put(long.class, new String2LongConvertorConcreteFactory());
...
}
public static ConvertorConcreteFactory createConvertorConcreteFactory(Class<T> type) {
return cachedConcreteFactories.get(type);
}
}
public class String2IntConvertorConcreteFactory implements ConvertorConcreteFactory {
public Convertor createConvertor() {
return new String2IntConvertor();
}
}
public class String2LongConvertorConcreteFactory implements ConvertorConcreteFactory {
public Convertor createConvertor() {
return new String2LongConvertor();
}
}
有人可能会说,工厂方法相比简单工厂方法更复杂了。工厂类再创建一个简单工厂,也就是工厂的工厂,用来创建工厂类对象。
如果每个工厂的创建只是简单的 new 就可以完成工厂的创建,功能比较单薄,我们没必要设计成一个独立的类,在这个场景下,简单工厂更合适。但是,如果对象的创建比较复杂,或许还要组合其他类对象,做各种初始化操作,此时应该更推荐使用工厂方法,将复杂的逻辑拆分到各个工厂类中,代码可读性、可扩展性会更好。
什么是抽象工厂?
抽象工厂,并没有简单工厂和工厂方法常用,这里简单了解即可。
在简单工厂和工厂方法,类只有一种,但是在抽象工厂中,类进行了扩充。
我们使用上面的例子进行延伸,现在有需求,String 的风格存在多种,因此需要支持多个转化器:
常规转化器:
String2IntConvertor
String2LongConvertor
风格A转化器
String2IntStyleAConvertor
String2LongStyleAConvertor
...
抽象工厂是怎么解决这样的设计问题呢?示例代码如下:
public interface ConvertorConcreteFactory {
Convertor createConvertor();
StyleAConvertor createStyleAConvertor();
}
public class String2IntConvertorConcreteFactory implements ConvertorConcreteFactory {
public Convertor createConvertor() {
return new String2IntConvertor();
}
public StyleAConvertor createStyleAConvertor() {
return new String2IntStyleAConvertor();
}
}
public class String2LongConvertorConcreteFactory implements ConvertorConcreteFactory {
public Convertor createConvertor() {
return new String2LongConvertor();
}
public StyleAConvertor createStyleAConvertor() {
return new String2LongStyleAConvertor();
}
}
抽象工厂就是针对这种非常特殊的场景而诞生的。单个工厂复杂创建多个不同类型的对象,而不是像简单工厂和工厂方法只创建一种对象,可以比较有效减少工厂类的个数,从而提高代码的可读性。