当前位置: 首页 > 后端技术 > Java

彻底解说你没关注过的简单工厂细节

时间:2023-04-01 19:15:07 Java

本文节选自《设计模式就该这样学》1使用简单工厂模型封装产品创建细节接下来我们看代码,还是拿创建一个以在线课程为例。假设有Java架构、大数据、人工智能等课程,一个生态已经形成。我们可以定义一个课程标准的ICourse接口。publicinterfaceICourse{/**录制视频*/publicvoidrecord();}创建一个Java课程实现类JavaCourse。publicclassJavaCourseimplementsICourse{publicvoidrecord(){System.out.println("RecordJavaCourse");}}客户端调用代码如下。publicstaticvoidmain(String[]args){ICoursecourse=newJavaCourse();course.record();}从上面代码可以看出,父类ICourse指向子类JavaCourse的引用,应用层代码需要依赖JavaCourse。如果业务扩大,PythonCourse会不断的加进去,甚至更多,那么客户端的依赖会越来越臃肿。因此,我们必须想办法弱化这种依赖,隐藏创建细节。虽然创建对象的过程在目前的代码中并不复杂,但从代码设计的角度来看并不容易扩展。因此,用简单工厂模式优化代码。首先添加类PythonCourse。publicclassPythonCourseimplementsICourse{publicvoidrecord(){System.out.println("记录Python课程");}}然后创建CourseFactory工厂类。publicclassCourseFactory{publicICoursecreate(Stringname){if("java".equals(name)){returnnewJavaCourse();}elseif("python".equals(name)){returnnewPythonCourse();}else{返回空值;}}}最后修改客户端调用代码。公共类SimpleFactoryTest{publicstaticvoidmain(String[]args){CourseFactoryfactory=newCourseFactory();factory.create("java");}}当然,为了调用方便,可以将CourseFactory的create()方法改为Static方法,其类图如下图所示。客户端调用虽然简单,但是如果业务不断扩大,增加前端课程,随着产品链的丰富,工厂中的create()方法每次都要修改代码逻辑,不符合开闭原则。因此,我们可以利用反射技术继续优化简单工厂模式,代码如下。公共课程CourseFactory{publicICoursecreate(StringclassName){try{if(!(null==className||"".equals(className))){return(ICourse)Class.forName(className).newInstance();}}catch(Exceptione){e.printStackTrace();}返回空值;}}客户端调用代码修改如下。publicstaticvoidmain(String[]args){CourseFactoryfactory=newCourseFactory();ICoursecourse=factory.create("com.gupaoedu.vip.pattern.factory.simplefactory.JavaCourse");course.record();}经过优化,产品不断丰富,无需修改CourseFactory中的代码。但问题是方法参数是字符串,可控性有待提高,还需要强制转换。继续修改代码。publicICoursecreate(Classclazz){try{if(null!=clazz){returnclazz.newInstance();}}}catch(Exceptione){e.printStackTrace();}returnnull;}优化客户端测试代码。publicstaticvoidmain(String[]args){CourseFactoryfactory=newCourseFactory();ICourse课程=factory.create(JavaCourse.class);course.record();}最后看下图所示的类图。2简单工厂模式在JDK源码中的应用简单工厂模式在JDK源码中无处不在,比如Calendar类,见Calendar.getInstance()方法。下面打开的是Calendar的具体创建类。privatestaticCalendarcreateCalendar(TimeZonezone,LocaleaLocale){CalendarProviderprovider=LocaleProviderAdapter.getAdapter(CalendarProvider.class,aLocale).getCalendarProvider();if(provider!=null){try{returnprovider.getInstance(zone,aLocale);}catch(IllegalArgumentExceptioniae){}}Calendarcal=null;如果(aLocale.hasExtensions()){Stringcaltype=aLocale.getUnicodeLocaleType("ca");if(caltype!=null){switch(caltype){case"buddhist":cal=newBuddhistCalendar(zone,aLocale);休息;case"japanese":cal=newJapaneseImperialCalendar(zone,aLocale);休息;case"gregory":cal=newGregorianCalendar(zone,aLocale);休息;}}}如果(cal==null){如果(aLocale.getLanguage()=="th"&&aLocale.getCountry()=="TH"){cal=newBuddhistCalendar(zone,aLocale);}elseif(aLocale.getVariant()=="JP"&&aLocale.getLanguage()=="ja"&&aLocale.getCountry()=="JP"){cal=newJapaneseImperialCalendar(zone,aLocale);}else{cal=newGregorianCalendar(zone,aLocale);}}returncal;}3简单工厂模式在Logback源码中的应用在大家经常使用的Logback中,可以看到LoggerFactory中有多个重载方法getLogger()publicstaticLoggergetLogger(Stringname){ILoggerFactoryiLoggerFactory=getILoggerFactory();返回iLoggerFactory。getLogger(name);}publicstaticLoggergetLogger(Classclazz){returngetLogger(clazz.getName());}关注微信公众号『汤姆炸弹架构』回复“设计模式”获取完整源码。【推荐】汤姆炸弹架构:30个设计模式实战案例(附源码),挑战60W年薪不是梦技术在于分享,我分享我的快乐!如果本文对您有帮助,请关注并点赞;有什么建议也可以留言或私信。您的支持是我坚持创作的动力。关注微信公众号『汤姆炸弹建筑』,获取更多技术干货!