工厂设计模式 抽象工厂
1.抽象工厂使用场景
使用端要不断创建某类对象,并且这类对象可以细分为不同种类。此时可以使用抽象工厂,其细分的种类由不同工厂创建。
2.原则
- 使用端依赖抽象
- 已经使用的类不再修改,扩展可以添加新的工厂
3.使用案例
需求:
肠粉店有许多功能相同的客户端,需要根据肠粉下单名称,创建肠粉订单对象。
肠粉可以分为广州口味,北京口味等的肠粉类型。
根据抽象工厂设计模式类图如下。
3.1类图
3.2代码
abstract class CF {
public void prepare();
public void cook() {
System.out.println("蒸肠粉");
}
public void oil() {
System.out.println("淋上肠粉酱油");
}
public void box() {
System.out.println("打包发货");
}
}
class BJEggCf extends CF {
public void prepare() {
System.out.println("准备北京口味的鸡蛋肠粉");
}
}
class GZEggCF extends CF {
public void prepare() {
System.out.println("准备广州口味的鸡蛋肠粉");
}
}
interface AbsFactory {
public CF createCF(String type);
}
class BJFactory implements AbsFactory {
public CF createCF(String type) {
if(type == "egg") {
return new BJEggCF();
}
}
}
class GZFactory implements AbsFactory {
public CF createCF(String type) {
if(type == "egg") {
return new GZEggCF();
}
}
}
//CF对象使用端
class Client1 {
AbsFactory absFactory;
public void setFactory(AbsFactory absFactory) {
this.absFactory = absFactory;
}
//返回客户下单的类型
String getType() {
return "egg";
}
public void createOrder() {
CF order = this,absFactory.createCF(this.getType);
}
}
class Client2 {
AbsFactory absFactory;
public void setFactory(AbsFactory absFactory) {
this.absFactory = absFactory;
}
//返回客户下单的类型
String getType() {
return "egg";
}
public void createOrder() {
CF order = this,absFactory.createCF(this.getType);
}
}
4.JDK源码分析
在JDK的Calender类中,就使用了工厂模式创建Calandar对象。
Calendar a = 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;
}