注意:该设计模式中的静态工厂方法模式与《effective java》中的静态工厂方法(static factory method)不同(这真是个坑)。关于《effective java》总的静态工厂方法替代构造函数产生实例,请参考 链接
一、概念
个人理解:静态工厂模式就是根据不同参数获取不同子类对象。
static:静态工厂模式由叫做简单工厂模式。然而,我更喜欢叫它静态工厂模式,因为它强调了静态
二字。在静态工厂模式的实现中,创建对象的工厂方法被定义为一个静态方法。
二、应用场景
当频繁根据参数创建某一个类的子类对象时,并且你不想实例化工厂类类时,建议使用静态工厂方法。
note:
当你想要改变工厂类创建对象的行为(也就是改变工厂方法)时,使用 另一个设计模式——工厂模式。
三、静态工厂模式的优缺点
优点:就是将根据参数创建某一个类的子类对象的代码提取出来,达到了代码复用的目的,避免频繁修改创建对象的代码。
note:
有人可能会问.
问:当我要添加新的类时,不是还是要修改静态工厂方法中创建对象的代码吗?这只不过是把问题搬到另一个对象罢了。
答:静态工厂方法的代码可以复用。比如你要在多个地方使用到这段创建对象的代码。
四、java源码中静态工厂模式的应用
java.text.DateFormat.getDateInstance()。DateFormat是一个抽象类,然而getDateInstance()却返回了它的子类。
4.1 测试代码
Date date=new Date();
DateFormat dateFormat=DateFormat.getDateInstance();
String temp=dateFormat.format(date);
System.out.println(temp);
运行结果
2019-1-23
- 进入getDateInstance()(其实还有带参数的getDateInstance方法)
public final static DateFormat getDateInstance()
{
return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
}
- 进入get方法
private static DateFormat get(int timeStyle, int dateStyle,
int flags, Locale loc) {
//对timeStyle,dateStyle进行一些校验设置
……
LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DateFormatProvider.class, loc);
DateFormat dateFormat = get(adapter, timeStyle, dateStyle, loc);//there
……
return dateFormat;
}
- 进入另一个get方法
private static DateFormat get(LocaleProviderAdapter adapter, int timeStyle, int dateStyle, Locale loc) {
DateFormatProvider provider = adapter.getDateFormatProvider();
DateFormat dateFormat;
if (timeStyle == -1) {
dateFormat = provider.getDateInstance(dateStyle, loc);//there
} else {
if (dateStyle == -1) {
dateFormat = provider.getTimeInstance(timeStyle, loc);
} else {
dateFormat = provider.getDateTimeInstance(dateStyle, timeStyle, loc);
}
}
return dateFormat;
}
- 进入provider真正的实现类sun.util.locale.provider.DateFormatProviderImpl的getDateInstance()中
public DateFormat getDateInstance(int var1, Locale var2) {
return this.getInstance(var1, -1, var2);
}
- 进入getInstance方法
private DateFormat getInstance(int var1, int var2, Locale var3) {
if (var3 == null) {
throw new NullPointerException();
} else {
SimpleDateFormat var4 = new SimpleDateFormat("", var3);
Calendar var5 = var4.getCalendar();
try {
String var6 = LocaleProviderAdapter.forType(this.type).getLocaleResources(var3).getDateTimePattern(var2, var1, var5);//there ,注意forType方法
var4.applyPattern(var6);
} catch (MissingResourceException var7) {
var4.applyPattern("M/d/yy h:mm a");
}
return var4;
}
}
- 进入LocaleProviderAdapter 的forType
public static LocaleProviderAdapter forType(LocaleProviderAdapter.Type var0) {
switch(var0) {
case CLDR:
return cldrLocaleProviderAdapter;
case HOST:
return hostLocaleProviderAdapter;
case JRE:
return jreLocaleProviderAdapter;
case SPI:
return spiLocaleProviderAdapter;
case FALLBACK:
return fallbackLocaleProviderAdapter;
default:
throw new InternalError("unknown locale data adapter type");
}
}
这里,终于到了静态工厂方法模式中的静态工厂方法了。这里我们更具var0参数,返回不同的LocaleProviderAdapter的子类。这里,return的时候没有new,是因为在类的初始化时,就初始化这些对象了。通过返回的LocleProviderAdapter,设置Date format的日期时间格式。
public abstract class LocaleProviderAdapter {
private static final List<LocaleProviderAdapter.Type> adapterPreference;
private static LocaleProviderAdapter jreLocaleProviderAdapter = new JRELocaleProviderAdapter();
private static LocaleProviderAdapter spiLocaleProviderAdapter = new SPILocaleProviderAdapter();
private static LocaleProviderAdapter cldrLocaleProviderAdapter = null;
private static LocaleProviderAdapter hostLocaleProviderAdapter = null;
private static LocaleProviderAdapter fallbackLocaleProviderAdapter = null;
static LocaleProviderAdapter.Type defaultLocaleProviderAdapter = null;
private static ConcurrentMap<Class<? extends LocaleServiceProvider>, ConcurrentMap<Locale, LocaleProviderAdapter>> adapterCache = new ConcurrentHashMap();
……
五、参考文献
《Head First 设计模式》(中文版)
简单工厂模式及静态工厂模式在jdk中的应用