1、工厂模式的历史由来
在现实生活中我们都知道,原始社会自给自足(没有工厂)、农耕社会小作坊(简单工厂,民间酒坊)、工业革命流水线(工厂方法,自产自销)、现代产业链代工厂(抽象工厂, 富士康)
2、简单工厂模式
简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类的实例,但它不属于 GOF,23 种设计模式。参考资料
简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。
首先,我们可以定义一个课程标准 ICourse 接口
public interface ICourse {
/** 录制视频 */
public void record();
}
创建一个 Java 课程的实现 JavaCourse 类:
public class JavaCourse implements ICourse {
public void record() {
System.out.println("录制 Java 课程");
}
}
创建 CourseFactory 工厂类:
public class CourseFactory {
public ICourse create(String name){
if("java".equals(name)){
return new JavaCourse();
}else if("python".equals(name)){
return new PythonCourse();
}else {
return null;
}
}
}
修改客户端调用代码:
public class SimpleFactoryTest {
public static void main(String[] args) {
CourseFactory factory = new CourseFactory();
factory.create("java");
}
}
当然,我们为了调用方便,可将 factory 的 create()改为静态方法,下面来看一下:
客户端调用是简单了,但如果我们业务继续扩展,要增加前端课程,那么工厂中的create() 就要根据产品链的丰富每次都要修改代码逻辑。不符合开闭原则。因此,我们对简单工厂还可以继续优化,可以采用反射技术:
public class CourseFactory {
public ICourse create(String className){
try {
if (!(null == className || "".equals(className))) {
return (ICourse) Class.forName(className).newInstance();
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
修改客户端调用代码:
public static void main(String[] args) {
CourseFactory factory = new CourseFactory();
ICourse course = factory.create("com.gupaoedu.vip.pattern.factory.simple factory.JavaCourse");
course.record();
}
优化之后,产品不断丰富不需要修改 CourseFactory 中的代码。但是,有个问题是,方法参数是字符串,可控性有待提升,而且还需要强制转型。我们再修改一下代码:
public ICourse create(Class<? extends ICourse> clazz){
try {
if (null != clazz) {
return clazz.newInstance();
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
优化客户端代码:
public static void main(String[] args) {
CourseFactory factory = new CourseFactory();
ICourse course = factory.create(JavaCourse.class);
course.record();
}
再看一下类图:
简单工厂模式在 JDK 源码也是无处不在,现在我们来举个例子,例如 Calendar 类,看 Calendar.getInstance()方法,下面打开的是 Calendar 的具体创建类:
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;
}
还有一个大家经常使用的 logback,我们可以看到 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());
}
简单工厂也有它的缺点:工厂类的职责相对过重,不易于扩展过于复杂的产品结构。