设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

本章主要介绍抽象工厂模式。

 

1.抽象工厂模式介绍

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

工厂方法模式针对的就是产品等级结构
而抽象方法模式针对的就是产品族
我们只要在美的产品族里面取空调,取出来的肯定是美的的空调,我们在美的的产品族里面取冰箱,取出来的肯定也是美的的电冰箱,只要我们确定这个产品的产品族和产品等级结构,我们就可以唯一的确定这个产品。

从理论上来说:当一个工厂可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,那这个时候,抽象工厂模式要比工厂方法模式要更为简单,更有效率。

2.抽象工厂模式Coding

现在,我们提一个业务场景,现在提出了新的要求:每一个课程不仅仅要有视频,还要有对应的手记,如果用工厂方法的方式来进行扩展的话 ,这个时候,既要有java的手记类,python的手记类,Spring的手记类,还有手记的抽象类,手记的工厂,java的手记的工厂,python的手记的工厂,Spring的手记的工厂,这个时候,就很容易出现类爆炸的现象.

原来是一个视频是一个课程,现在一个视频加上一个手记是一个课程


java视频,python视频,Spring视频他们属于同一产品等级,都是视频
java手记,python手记,Spring手记他们也属于同一产品等级,都是手记

而java手记,java视频他们处于同一产品族,都是java相关的;
同一产品族,我们就看java,还是python还是Spring;
同一产品等级,我们就看它是视频还是手记即可。


创建一个课程工厂:

视频类:

/**
 * @author Merlin
 * @Title: Video
 * @ProjectName java-base-learning
 * @Description: 视频抽象类
 * @date 2019/3/414:27
 */
public abstract class Video {

    public abstract void produce();
}

手记类:

/**
 * @author Merlin
 * @Title: Article
 * @ProjectName java-base-learning
 * @Description: 手记抽象类
 * @date 2019/3/415:25
 */
public abstract class Article {

    public abstract void produce();
}

课程工厂类:

/**
 * @author Merlin
 * @Title: CourseFactory
 * @ProjectName java-base-learning
 * @Description: 课程接口工厂类
 * @date 2019/3/415:26
 */
public interface CourseFactory {

    /** 获取视频 */
    Video getVideo();

    /** 获取手记 */
    Article getArticle();
}

创建java产品族的课程工厂:

Java视频类:

/**
 * @author Merlin
 * @Title: JavaVideo
 * @ProjectName java-base-learning
 * @Description: Java视频类
 * @date 2019/3/415:30
 */
public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("录制Java课程视频");
    }
}

Java手记类:

/**
 * @author Merlin
 * @Title: JavaArticle
 * @ProjectName java-base-learning
 * @Description: java手记类
 * @date 2019/3/415:32
 */
public class JavaArticle extends Article {
    @Override
    public void produce() {
        System.out.println("编写Java课程手记");
    }
}

产品族里面的工厂类:

/**
 * @author Merlin
 * @Title: JavaCourseFactory
 * @ProjectName java-base-learning
 * @Description: 创建java产品族的课程工厂
 * 这里讲视频工厂和手记工厂合在一起作为一个产品族
 * @date 2019/3/415:27
 */
public class JavaCourseFactory implements CourseFactory {
    @Override
    public Video getVideo() {
        return new JavaVideo();
    }

    @Override
    public Article getArticle() {
        return new JavaArticle();
    }
}

这里就是把视频工厂和手记工厂合在了一起;作为一个产品族。


我们再来写一个python的产品族的:
PythonArticle类:

/**
 * @author Merlin
 * @Title: pythonArticle
 * @ProjectName java-base-learning
 * @Description: python课程手记
 * @date 2019/3/415:49
 */
public class PythonArticle extends Article{
    @Override
    public void produce() {
        System.out.println("编写Python课程手记");
    }
}

PythonVideo 类:

/**
 * @author Merlin
 * @Title: PythonVideo
 * @ProjectName java-base-learning
 * @Description: python视频类
 * @date 2019/3/416:04
 */
public class PythonVideo extends Video{
    @Override
    public void produce() {
        System.out.println("录制Python的视频");
    }
}

现在,我们再来创建Python产品族的课程工厂(视频和手记合在了一起):

/**
 * @author Merlin
 * @Title: PythonCourseFactory
 * @ProjectName java-base-learning
 * @Description: Python产品族的课程工厂
 * @date 2019/3/416:12
 */
public class PythonCourseFactory implements CourseFactory {
    @Override
    public Video getVideo() {
        return new PythonVideo();
    }

    @Override
    public Article getArticle() {
        return new PythonArticle();
    }
}

类图:

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

测试:
只要是从Java产品族里面拿的肯定是Java的视频和Java的手记

public class Test {
    public static void main(String[]args){
        CourseFactory courseFactory = new JavaCourseFactory();
        Article article = courseFactory.getArticle();
        Video video = courseFactory.getVideo();
        /** 只要是从Java产品族里面拿的肯定是Java的视频和Java的手记 */
        article.produce();
        video.produce();
    }
}

运行结果:

编写Java课程手记
录制Java视频

3.总结

总结:
优点: 解耦程度高;
     在使用抽象工厂的时候,尽量找那种固定程度比较高的,像课程里面的视频和手记,视频和手记都是必须要有的,就可以用抽象工厂模式来解决;
缺点:在新增产品等级的时候,会比较的麻烦;
     如果在现有的产品族里面添加新的产品等级,就违背了开闭原则了;
     如果我们还要把源码放到课程的这个产品族里面,那么对原来的修改就比较大了;

 

4.抽象工厂结合实例源码分析

MySql中的Connection:

java.sql.Connection 接口中许多方法,都是抽象方法。

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

Statement
PreparedStatement
在Connection接口中返回的都是同一个产品族。
例如:我们创建一个Mysql的产品族或sqlserver。无论创建的
Statement或者是PreparedSatement。创建的都是对应的DB的连接。
所以说:Connection定义的方法,都属于同一个产品族。
Statement接口中的一些方法,也都是需要子类实现。也是一个抽象工厂。
从该接口中获取的也都是同一产品族。


MyBatis中的SqlSessionFactory:

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

设计模式精讲 | 笔记(五) | 抽象工厂模式coding与源码分析

通过源码可以看出,SqlSession,Confguration 这两种类型无论是Mysql,还是
SqlServer获取的。都是属于同一产品族。
SqlSession中所做的事情非常多。

也可以从图中可以看出,其中一个默认实现方法DefaultSqlSession与SqlSession两个类之间的联系是抽象工厂模式

 

主要来源:geely老师设计模式视频

相关代码:

Github地址:https://github.com/CoderMerlin/java-base-learning/tree/master/java-design-learning

Gitee地址:  https://gitee.com/573059382/java-base-learning

欢迎关注并点赞~