序
定义
- 由一个工厂对象决定创建出哪一种产品类的实例
类型
- 创建型。但不属于GOF23种设计模式
适用场景
- 工厂类负责创建的对象比较少
- 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心
优点
- 解耦
- 只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节,明确了各个模块的职责权限
- 工厂类中包含了必要的判断逻辑,根据客户端的选择条件,动态实例化相关类,对于客户端来说,去除了具体产品的依赖
缺点
- 工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,违背开闭原则
- 无法形成基于继承的等级结构
代码示例
假设我们现在想吃红烧肉和明炉烧鸭。那我们应该怎么做。
- 先创建一个抽象食物类。里面声明一个烹饪的抽象方法
public abstract class Food {
//烹饪
public abstract void cuisine();
}
- 分别创建 红烧肉和明炉烧鸭,并继承Food抽象类
public class RoastDuck extends Food{
@Override
public void cooking() {
System.out.println("明炉烧鸭烹饪完成..");
}
}
public class Bouilli extends Food{
@Override
public void cooking() {
System.out.println("红烧肉烹饪完成..");
}
}
- 那我们怎么吃到这两道菜呢,别的地也没得吃,但是我作为一个资深吃货,自己会做呀。
public class Foodie {
public static void main(String[] args) {
Food bouilli = new Bouilli();
bouilli.cooking();
Food roastDuck = new RoastDuck();
roastDuck.cooking();
}
}
这样我们就把这两道菜做完了。
现在的uml是这样的
- 后来我跟我们邻居说了这件事。他说就这两个菜还需要自己做,楼下的餐厅就有呀,于是就有了下面的餐厅类(工厂类)
public class DiningRoom {
public static Food orderDishes(String name){
Food food = null;
switch (name) {
case "Bouilli":
food = new Bouilli();
break;
case "RoastDuck":
food = new RoastDuck();
break;
default:
break;
}
return food;
}
}
- 之后我想吃的时候直接去他们餐厅点菜就好了。
public class Foodie {
public static void main(String[] args) {
Food bouilli = DiningRoom.orderDishes("Bouilli");
bouilli.cooking();
Food roastDuck = DiningRoom.orderDishes("RoastDuck");
roastDuck.cooking();
}
}
uml关系
现在我们就不用关心他们是怎么做的了。我们只需要点菜就好了。但是这家餐厅点菜有些麻烦呢。每次都让我写下菜单名字。为什么我不能直接看着菜选呢。在我吃完饭之后我给老板提了下意见,老板欣然采纳。
- 等我再一次去得时候果然变了,首先是他们餐厅点菜模式。
public class DiningRoom {
public static Food orderDishes(Class clazz){
Food food = null;
try{
food = (Food) Class.forName(clazz.getName()).newInstance();
}catch (Exception e){
e.printStackTrace();
}
return food;
}
}
- 我点菜的时候也开心的对着菜单点了
public class Foodie {
public static void main(String[] args) {
Food bouilli = DiningRoom.orderDishes(Bouilli.class);
bouilli.cooking();
Food roastDuck = DiningRoom.orderDishes(RoastDuck.class);
roastDuck.cooking();
}
}
老板说这样一改好多了。按原来的那种模式他们每次加一种菜,都要修改他们的点餐逻辑。
现在这样,他们只管加菜,并且把菜名让大家知道,让大家看着菜点那我们有的我们就做,没有的就抛出异常让点菜的人知道(用反射来弥补简单工厂自身的缺点,已符合对修改关闭,扩展开发的开闭原则,因为用到反射效率会低一些)
开源框架中的应用
- JDK java.util.Calendar
找到getInstance方法
public static Calendar getInstance()
{
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
接着我们去查看createCalendar方法具体实现
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) {
}
}
Calendar cal = null;
//以下逻辑是不是跟我上边代码示例中第一次去餐厅那个点餐模式一样
//都通过简单的条件判断,然后把对应的子类实现return。
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 (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;
}
uml如如下
- logback org.slf4j.LoggerFactory
找到getLogger方法
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
public static Logger getLogger(Class clazz) {
return getLogger(clazz.getName());
}
进入ch.qos.logback.classic.getLogger方法
public final Logger getLogger(String name) {
if(name == null) {
throw new IllegalArgumentException("name argument cannot be null");
} else if("ROOT".equalsIgnoreCase(name)) {
return this.root;
} else {
int i = 0;
Logger logger = this.root;
Logger childLogger = (Logger)this.loggerCache.get(name);
if(childLogger != null) {
return childLogger;
} else {
int h;
do {
h = LoggerNameUtil.getSeparatorIndexOf(name, i);
String childName;
if(h == -1) {
childName = name;
} else {
childName = name.substring(0, h);
}
i = h + 1;
synchronized(logger) {
childLogger = logger.getChildByName(childName);
if(childLogger == null) {
childLogger = logger.createChildByName(childName);
this.loggerCache.put(childName, childLogger);
this.incSize();
}
}
logger = childLogger;
} while(h != -1);
return childLogger;
}
}
}
这也是一个简单工厂的实现。这个实现里既存在工厂方法,也存在了简单工厂,所以设计模式在使用的时候不局限在使用一种,例如这里就是组合使用