工厂模式详解(1)--简单工厂模式

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());
}

简单工厂也有它的缺点:工厂类的职责相对过重,不易于扩展过于复杂的产品结构。

猜你喜欢

转载自blog.csdn.net/weixin_46822085/article/details/108837389