3.抽象工厂模式
3.1 概述
定义:抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口
(无需指定它们具体的类)
类型:创建型
适用场景:
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码
- 提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现
优点:
- 具体产品在应用层代码隔离,无需关心创建细节
- 将一个系列的产品族一起创建
缺点:
- 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
- 增加了系统的抽象性和理解难度
一些概念:
产品等级结构和产品族
比如 美的有生产 电磁炉、微波炉和空调(对应一排中的正方形、圆形和椭圆形),它们同一排颜色相同的是一个产品族;同理第二排理解为海尔的对应的各类电器…也是一个产品族。
在一列中比如第一列,表示不同厂家的电磁炉,它们构成一个相同的产品等级。
工厂方法
针对的是产品等级结构;抽象工厂
针对的是产品族,我们在美的的产品族(一个具体工厂)中做取电磁炉操作,就肯定是美的的电磁炉。
3.2 代码理解
场景:
原有需求
:教学网站有不同种类的教学视频,Java、Python等,想新增什么教学视频时,从把想要的类型传 给 视频工厂,然后生产出视频。
新增需求
:教学网站对不同种类课程需要加入手记,Java视频要配套Java手记;Python视频要配套Python手记才是一门完整的课程。
如果使用工厂方法模式的话,需要创建 手记类、各类课程的手记类、手记工厂类、各类手记工厂类等,可能出现类爆炸的状况。
此时
- Python视频和Python手记属于Python产品族(才算是完整的Python课程);Java视频和Java手记属于Java产品族(才算是完整的Java课程);
- Python视频和Java视频属于教学视频产品等级;Python手记和Java手记属于教学手记产品等级。
coding
新建Article
手记抽象类:
package com.gangbb.creational.abstractfactory;
/**
* @author Gangbb
* @date 2021/3/29 13:30
* @Description: 手记抽象类
*/
public abstract class Article {
/**
* 生产方法
*/
public abstract void produce();
}
新建Video
视频抽象类:
package com.gangbb.creational.abstractfactory;
/**
* @author Gangbb
* @date 2021/3/29 13:30
* @Description: 视频类
*/
public abstract class Video {
/**
* 生产方法
*/
public abstract void produce();
}
Java和Python的视频和手记实现类
package com.gangbb.creational.abstractfactory;
/**
* @author Gangbb
* @date 2021/3/29 13:57
* @Description: python手记类
*/
public class PythonArticle extends Article{
/**
* 生产Python手记方法
*/
public void produce() {
System.out.println("生产Python手记方法");
}
}
package com.gangbb.creational.abstractfactory;
/**
* @author Gangbb
* @date 2021/3/29 13:55
* @Description: python视频类
*/
public class PythonVideo extends Video{
/**
* 生产python视频方法
*/
public void produce() {
System.out.println("生产python视频");
}
}
package com.gangbb.creational.abstractfactory;
/**
* @author Gangbb
* @date 2021/3/29 13:56
* @Description: Java手记类
*/
public class JavaArticle extends Article{
/**
* 生产Java手记方法
*/
public void produce() {
System.out.println("生产Java手记");
}
}
package com.gangbb.creational.abstractfactory;
/**
* @author Gangbb
* @date 2021/3/29 13:54
* @Description: Java视频类
*/
public class JavaVideo extends Video {
/**
* 生产Java视频方法
*/
public void produce() {
System.out.println("生产Java视频");
}
}
课程工厂接口CourseFactory
package com.gangbb.creational.abstractfactory;
/**
* @author Gangbb
* @date 2021/3/29 13:29
* @Description: 课程工厂接口
*/
public interface CourseFactory {
/**
* 获取教学视频
* @return
*/
Video getVideo();
/**
* 获取教学手记
* @return
*/
Article getArticle();
}
JavaCourseFactory
Java课程工厂类
package com.gangbb.creational.abstractfactory;
/**
* @author Gangbb
* @date 2021/3/29 13:51
* @Description: Java课程工厂类
*/
public class JavaCourseFactory implements CourseFactory{
/**
* 获取Java教学视频
*
* @return
*/
public Video getVideo() {
return new JavaVideo();
}
/**
* 获取Java教学手记
*
* @return
*/
public Article getArticle() {
return new JavaArticle();
}
}
PythonCourseFactory
python课程工厂
package com.gangbb.creational.abstractfactory;
/**
* @author Gangbb
* @date 2021/3/29 14:01
* @Description: python课程工厂
*/
public class PythonCourseFactory implements CourseFactory {
/**
* 获取Python教学视频
*
* @return
*/
public Video getVideo() {
return new PythonVideo();
}
/**
* 获取Python教学手记
*
* @return
*/
public Article getArticle() {
return new PythonArticle();
}
}
此时类图
应用层Client
package com.gangbb.creational.abstractfactory;
/**
* @author Gangbb
* @date 2021/3/29 14:10
* @Description:
*/
public class Client {
public static void main(String[] args) {
CourseFactory courseFactory = new JavaCourseFactory();
Video video = courseFactory.getVideo();
Article article = courseFactory.getArticle();
video.produce();
article.produce();
}
}
只需要从课程工厂调用生成方法即可,无需关注内部的生成过程。想要Java视频在Java工厂中获取的肯定就是Java视频。
新增产品族容易,新增产品等级要做较大更改,这也是抽象工厂的弊端。
3.3 开源框架源码使用分析
3.3.1 JDK数据库连接接口抽象工厂示例
java.sql.Connection
3.3.2 Mybatis中SqlSessionFactory
org.apache.ibatis.session.SqlSessionFactory
可以看到这里面的类有返回SqlSession
和Configuration
,所以只要通过SqlSessionFactory
获取的这两种类型肯定属于同一个产品族,可能是mysql
的SqlSessionFactory
也可能是SQL server
的SqlSessionFactory
,获取的结果肯定是同一产品族。