1. 简单工厂模式
1.1 介绍
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,**我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。**常见的工厂模式有简单工厂模式、工厂方法模式、抽象工程模式等。
1.2 优缺点
优点
- 调用者只需要使用工厂即可,而不用亲自书写创建对象的代码,减少了代码量
- 扩展性高,如果想增加一个产品,只需要扩展一个工厂即可
- 屏蔽产品的具体实现,实现了代码层面的解耦
缺点
- 增加产品时需要扩展工厂,增加了系统的复杂度,也增加了系统具体类的依赖
- 当需要添加新产品时,需要在工厂内部进行修改,不符合"开—闭原则"
1.3 使用场景
- 经常创建某对象时,可以使用工厂模式,比如Spring的bean工厂
1.4 注意事项
- 工厂模式适用于创建复杂对象,而简单对象无需工厂模式,如通过new就可以完成创建的对象
2. 案例实现
注意
在之后的24篇设计模式中,本文全部以造车作为出发点来进行案例代码设计。
我来到4S店买车,我说:“老板,给我来辆奥迪”。老板去汽车厂里调了一台奥迪来了,我又说,来一辆宝马,老板又去宝马车厂里调了一台宝马来了。我又准备说,老板说等等,我好累,让我歇会。
abstract class Car{
abstract String getName();
}
class BMW extends Car{
@Override
String getName() {
return "宝马";
}
}
class Audi extends Car{
@Override
String getName() {
return "奥迪";
}
}
class CarSimpleFactory{
public static Car getCar(String name){
if(name == "宝马"){
return new BMW();
}else if(name == "奥迪"){
return new Audi();
}
return new Audi();
}
}
/** * 简单工厂模式 * 通过实现工厂类来创建产品 * * @Author cly * @Date 2021/08/30 23:37 * @Version 1.0 */
public class SimpleFactory {
public static void main(String[] args) {
Car car = CarSimpleFactory.getCar("宝马");
System.out.println(car.getName());
}
}
3. 源码实现
3.1 JDK中Calendar中
可以说简单工厂模式在 JDK 源码中无处不在,下面以 Calendar 类为例讲解简单工厂模式在 JDK 源码中的应用。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
}
}
Calendar cal = null;
if (aLocale.hasExtensions()) {
String caltype = aLocale.getUnicodeLocaleType("ca");
if (caltype != null) {
switch (caltype) {
case "buddhist":
cal = new BuddhistCalendar(zone, aLocale);
break;
case "japanese":
cal = new JapaneseImperialCalendar(zone, aLocale);
break;
case "gregory":
cal = new GregorianCalendar(zone, aLocale);
break;
}
}
}
if (cal == null) {
// If no known calendar type is explicitly specified,
// perform the traditional way to create a Calendar:
// create a BuddhistCalendar for th_TH locale,
// a JapaneseImperialCalendar for ja_JP_JP locale, or
// a GregorianCalendar for any other locales.
// NOTE: The language, country and variant strings are interned.
if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
cal = new BuddhistCalendar(zone, aLocale);
} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
&& aLocale.getCountry() == "JP") {
cal = new JapaneseImperialCalendar(zone, aLocale);
} else {
cal = new GregorianCalendar(zone, aLocale);
}
}
return cal;
}