工厂模式
本文主要结合实例讲解
- 简单工厂模式
简单工厂模式
简单工厂模式(Simple Factory Pattern)是指一个工厂对象决定创建哪一种产品类的实例,但它不属于GoF(Gang of Four)的 23 种设计模式。简单工行模式适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象不需要关心。
以课程为例,我们定义一个课程标准接口ICourse接口:
public interface ICourse {
/**
* 录制视频
*/
public void record();
}
创建一个Java课程的实现 JavaCourse类:
public class JavaCourse implements ICourse {
@Override
public void record() {
System.out.println("录制java课程");
}
}
客户端调用代码:
public class Main {
public static void main(String[] args) {
ICourse course = new JavaCourse();
course.record();
}
}
在上面代码中,父类ICourse指向子类JavaCourse的引用,应用层代码需要依赖JavaCourse,如果业务扩展,继续增加别的课程,那么客户端的依赖会变得越来越臃肿。因此,我们要想办法把这种依赖减弱,把创建细节隐藏起来。虽然在目前的代码中,常见对象的过程并不复杂,但是不易于扩展。现在我们用简单工厂模式对代码进行优化。先增加课程类PythonCourse:
public class PythonCourse implements ICourse {
@Override
public void record() {
System.out.println("录制python课程");
}
}
创建课程工厂:
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 static void main(String[] args) {
CourseFactory factory = new CourseFactory();
ICourse course = factory.create("java");
course.record();
}
可以将工厂中的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 class Main {
public static void main(String[] args) {
CourseFactory factory = new CourseFactory();
ICourse course = factory.create("com.tan.facyory.JavaCourse");//包名加类名
course.record();
}
}
优化之后,产品不断丰富的过程中不需要修改CourseFactory中的代码。但是方法参数是字符串,所以继续修改:
public class CourseFactory {
public ICourse create(Class<? extends ICourse> clazz){
try {
if (null != clazz){
return clazz.newInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
客户端代码:
public class Main {
public static void main(String[] args) {
CourseFactory factory = new CourseFactory();
ICourse course = factory.create(JavaCourse.class);
course.record();
}
}
在看一下类图:
简单工厂模式在JDK源码中也无处不在,比如说Calender类中的getInstance()方法。
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;
}
简单工厂模式的缺点:工厂类的职责相对过重,不易于扩展复杂的产品结构
其他工厂模式
后面会继续更新
- 工厂方法模式
- 抽象工厂模式