文章目录
1.简单工厂模式
1.1 概述
定义:由一个工厂对象决定创建出哪一种产品类的实例
类型:
- 创建型,但不属于GOF23种设计模式
适用场景:
- 工厂类负责创建的对象比较少
- 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心
优点:
1、工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;
2、简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
3、客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
4、通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点:
1、由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
2、使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
3、系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
4、简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
5、无法形成基于继承的逻辑结构
1.2 代码理解
1.2.1 常规实现
场景:
教学网站有不同种类的教学视频,Java、Python等,想新增什么教学视频时,从把想要的类型传给 视频工厂,然后生产出视频。
Video视频基类:
package com.gangbb.creational.simplefactory;
/**
* @author Gangbb
* @date 2021/3/27 20:44
*/
public abstract class Video {
/**
* 生产视频
*/
public abstract void produce();
}
JavaVideoJava视频类:
package com.gangbb.creational.simplefactory;
/**
* @author Gangbb
* @date 2021/3/27 20:45
*/
public class JavaVideo extends Video{
/**
* 生产java视频
*/
public void produce() {
System.out.println("创建Java视频");
}
}
PythonVideoPython视频类:
package com.gangbb.creational.simplefactory;
/**
* @author Gangbb
* @date 2021/3/27 20:46
*/
public class PythonVideo extends Video{
/**
* 生产python视频
*/
public void produce() {
System.out.println("生产python视频");
}
}
传统使用方法:
Client客户端调用类:
package com.gangbb.creational.simplefactory;
/**
* @author Gangbb
* @date 2021/3/27 20:47
* @Description: 模拟客户端类
*/
public class Client {
public static void main(String[] args) {
//创建Java视频
Video video = new JavaVideo();
video.produce();
}
}
此时类图:

加入视频简单工厂类:
VideoFactory视频简单工厂类:
package com.gangbb.creational.simplefactory;
/**
* @author Gangbb
* @date 2021/3/27 20:49
* @Description: 视频简单工厂
*/
public class VideoFactory {
public Video getVideo(String type){
if("java".equalsIgnoreCase(type)){
return new JavaVideo();
}else if ("python".equalsIgnoreCase(type)){
return new PythonVideo();
}
return null;
}
}
PS:这里
getVideo方法也可以写成静态方法
Client客户端调用类 中使用:
package com.gangbb.creational.simplefactory;
/**
* @author Gangbb
* @date 2021/3/27 20:47
* @Description: 模拟客户端类
*/
public class Client {
public static void main(String[] args) {
//传统调用-----创建Java视频
//Video video = new JavaVideo();
//video.produce();
//使用 视频简单工厂--创建视频
VideoFactory videoFactory = new VideoFactory();
Video video = videoFactory.getVideo("java");
video.produce();
}
}
此时类图:

1.2.1 反射实现
修改常规实现中的VideoFactory中的getVideo方法:
package com.gangbb.creational.simplefactory;
/**
* @author Gangbb
* @date 2021/3/27 20:49
* @Description: 视频简单工厂
*/
public class VideoFactory {
/**
* 反射实现getVideo
* @param T
* @return
*/
public Video getVideo(Class T){
Video video = null;
try {
video = (Video) Class.forName(T.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return video;
}
}
在Client中调用:
package com.gangbb.creational.simplefactory;
/**
* @author Gangbb
* @date 2021/3/27 20:47
* @Description: 模拟客户端类
*/
public class Client {
public static void main(String[] args) {
//传统调用-----创建Java视频
//Video video = new JavaVideo();
//video.produce();
//使用 视频简单工厂--创建视频(常规实现)
// VideoFactory videoFactory = new VideoFactory();
// Video video = videoFactory.getVideo("java");
// video.produce();
//使用 视频简单工厂--创建视频(反射实现)
VideoFactory videoFactory = new VideoFactory();
Video video = videoFactory.getVideo(PythonVideo.class);
video.produce();
}
}
1.3 源码使用分析
1.3.1 JDK源码使用简单工厂示例
Java的日历工具类java.util.Calendar
其中有一个getInstance方法:

调用了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) {
// 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;
}
该类的类图:

1.3.2 spring使用简单工厂示例
实现⽅式:
BeanFactory。Spring中的BeanFactory就是简单⼯⼚模式的体现,根据传⼊⼀个唯⼀的标识来获得Bean对象,但是否是在传 ⼊参数后创建还是传⼊参数前创建这个要根据具体情况来定。 实质: 由⼀个⼯⼚类根据传⼊的参数,动态决定应该创建哪⼀个产品类。
实现原理:
bean容器的启动阶段:
-
读取bean的xml配置⽂件,将bean元素分别转换成⼀个BeanDefinition对象。
-
然后通过BeanDefinitionRegistry将这些bean注册到beanFactory中,保存在它的⼀个ConcurrentHashMap中。
-
将BeanDefinition注册到了beanFactory之后,在这⾥Spring为我们提供了⼀个扩展的切⼝,允许我们通过实现接⼝ BeanFactoryPostProcessor 在此处来插⼊我们定义的代码。
典型的例⼦就是:PropertyPlaceholderConfigurer,我们⼀般在配置数据库的dataSource时使⽤到的占位符的值,就是 它注⼊进去的。
容器中bean的实例化阶段:
实例化阶段主要是通过反射或者CGLIB对bean进⾏实例化,在这个阶段Spring⼜给我们暴露了很多的扩展点:
-
各种的Aware接⼝,⽐如 BeanFactoryAware,对于实现了这些Aware接⼝的bean,在实例化bean时Spring会帮我们注 ⼊对应的BeanFactory的实例。
-
BeanPostProcessor接⼝,实现了BeanPostProcessor接⼝的bean,在实例化bean时Spring会帮我们调⽤接⼝中的⽅ 法。
-
InitializingBean接⼝,实现了InitializingBean接⼝的bean,在实例化bean时Spring会帮我们调⽤接⼝中的⽅法。
-
DisposableBean接⼝,实现了BeanPostProcessor接⼝的bean,在该bean死亡时Spring会帮我们调⽤接⼝中的⽅法。
设计意义:
松耦合。可以将原来硬编码的依赖,通过Spring这个beanFactory这个⼯⼚来注⼊依赖,也就是说原来只有依赖⽅和被依赖⽅, 现在我们引⼊了第三⽅——spring这个beanFactory,由它来解决bean之间的依赖问题,达到了松耦合的效果.bean的额外处理。通过Spring接⼝的暴露,在实例化bean的阶段我们可以进⾏⼀些额外的处理,这些额外的处理只需要让bean 实现对应的接⼝即可,那么spring就会在bean的⽣命周期调⽤我们实现的接⼝来处理该bean。 [⾮常重要
1.3.3 slf4j使用简单工厂示例
org.slf4j.LoggerFactory
有一个getLogger方法
/**
* Return a logger named according to the name parameter using the statically
* bound {@link ILoggerFactory} instance.
*
* @param name The name of the logger.
* @return logger
*/
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
/**
* Return a logger named corresponding to the class passed as parameter, using
* the statically bound {@link ILoggerFactory} instance.
*
* @param clazz the returned logger will be named after clazz
* @return logger
*/
public static Logger getLogger(Class clazz) {
return getLogger(clazz.getName());
}
这里很明显就是根据入参 选择实现的log实现方法。
798

被折叠的 条评论
为什么被折叠?



