在面向对象的编程中,工厂就是用来生产对象的。
因为对象的创建往往都很复杂,工厂对外提供创建对象的接口,将对象的实例化逻辑细节进行封装。
就像生活中,工厂产生商品,商家只需要拿到商品去做生意就行了,不关心商品生产的细节。
常见的工厂模式由,简单工厂模式、工厂方法模式、抽象工厂模式。
简单工厂基本概念:
SimpleFfactory:简单工厂。
Product: 商品接口。
ConcreateProduct1: 商品接口具体实现类1。
ConcreateProduct2: 商品接口具体实现类1。
现在网络教育很火,本文以课程为商品product,写了几个例子。
简单工厂类CourseFactory
简单工厂 : 根据传参创建对象,屏蔽创建细节。
缺点: 每次创建一个新产品,需要新增一个方法,不易于扩展,违背开闭原则
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 ICourse create(Class clazz) {
try {
if(null!= clazz){
return (ICourse) clazz.newInstance();
}
}catch (Exception e){
e.printStackTrace();
}
return null;
}
}
课程接口ICourse
public interface ICourse {
public void record();
}
java课程JavaCource
public class JavaCource implements ICourse {
@Override
public void record() {
System.out.println("这是java课程");
}
}
python课程PythonCourse
public class PythonCourse implements ICourse {
@Override
public void record() {
System.out.println("这个是 phthy课程");
}
}
工厂方法模式,工厂类被抽象化,用于实例化特定产品类的代码被转移到实现抽象方法的子类中,这样不需要修改就可以扩展工厂类了。
工厂方法模式:
优点:用户只关心产品, 符合开闭原则,提高系统扩展性
缺点: 类的个数过多,增加了代码结构的复杂度,增加了系统的抽象性、复杂性
工厂方法类ICourseFactory
public abstract class ICourseFactory {
public void preCource(){};
abstract ICourse create();
}
具体工厂类1 JavaCourseFactory
public class JavaCourseFactory extends ICourseFactory {
@Override
public ICourse create() {
return new JavaCource();
}
}
具体工厂类2 PythonCourseFactory
public class PythonCourseFactory extends ICourseFactory {
@Override
public ICourse create() {
return new PythonCourse();
}
}
具体的课程类在简单工厂有,不重复写了。
抽象工厂模式是工厂方法模式的扩展版本。它不是创建单一类型的对象,而是创建一系列相关联的对象。如果工厂方法模式中只包含一个抽象产品类,那么抽象工厂模式则包含多个抽象产品类。
在工厂方法中只有一个抽象方法,在不同的具体工厂类中分别实现抽象产品的实例化,而抽象工厂中,每个产品都有一个实例化方法。
如果采用抽象工厂并将它应用于单个对象的簇,那么就得到了工厂方法模式。
举个例子:现在的网课都配套了笔记、源码、视频等等,万物皆为对象,万物皆可抽象。例如java课配套java
专属的笔记、源码、视频。python课配套python的笔记、视频、源码等等。
那么如何将其用工厂模式进行创建了,利用上面的思想将工厂抽象化,具体工厂产生对应具体工厂的对象。代码如下。
抽象工厂ICourseFactory
/**
* 所有子工厂都实现本接口
* 一个品牌的抽象
* 抽象工厂不符合开闭原则,但是易于扩展
*/
public interface ICourseFactory {
ICourse createCourse();
INote createNote();
IVideo createVideo();
ISource createSource();
}
具体的java课程工厂类JavaCourseFactory
public class JavaCourseFactory implements ICourseFactory {
@Override
public ICourse createCourse() {
return new JavaCource();
}
@Override
public INote createNote() {
return new JavaNote();
}
@Override
public IVideo createVideo() {
return new JavaVideo();
}
@Override
public ISource createSource() {
return new JavaSource();
}
}
具体python课程工厂类
public class PythonFactory implements ICourseFactory {
@Override
public ICourse createCourse() {
return new PythonCource();
}
@Override
public INote createNote() {
return new PythonNote();
}
@Override
public IVideo createVideo() {
return new PythonVideo();
}
@Override
public ISource createSource() {
return new PythonSource();
}
}
笔记接口INote
public interface INote {}
源码接口ISource
public interface ISource {}
视频接口IVideo
public interface IVideo {}
具体的课程,笔记、视频源码类不叙述了,就是实现了相应的接口。
首先类看一看常见的BeanFactory的类的继承关系图(注意:只截取了部分常见的继承关系)。
spring中的BeanFacotry继承关系很复杂,它的工厂模式也相当复杂,比上述的三种工厂模式都要复杂很多。
它是先有beanFactory的顶级接口。同时扩展了带有很多功能性的二级beanFactory接口,然后再抽象出一层抽象工厂类AbstractBeanFactory,最后给beanFactory一个默认实现DefaultListBeanFactory(spring ioc的底层容器,有兴趣的同学可以看看我的源码分析系列,目前正在分析spring源码1、spring源码解析之概况流程。)
但是经常看spring源码的小伙伴相信都有自己阅读源码的方式。
但是我总结一些自己的小技巧。通常spring源码读起来很复杂,主要是类的继承关系相当繁多,很容易让人失去继续阅读的兴趣,但是如果你抓住技巧,找到正确的继承关系,耐心的读下去,弄清楚调用逻辑。多读几遍,抓住主体线,或通过时序图的方式记录调用的逻辑,其实源码读起来也不复杂。坚持才会有所收获。
未完待续