IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring中常用的设计模式——工厂模式 -> 正文阅读

[Java知识库]Spring中常用的设计模式——工厂模式

一、简单工厂模式

简单工厂模式也被称为静态工厂模式,它是指由一个工厂对象决定创建哪一种产品的实例。
简单举个例子,在原始社会,我们需要自给自足。在工业革命之后,世界上出现了各种各样的代工厂、流水线,人们只需要买来需要的产品,并且知道如何使用就行了。那么简单工厂模式也是如此,它可以将产品的使用和生产完全分开,客户端只需要知道需要什么产品,如何来使用产品的就可以了,而具体的产品生产任务由具体的工厂类来实现。
在现实的工厂中,如果大量的、多种类型的产品都在一个工厂生产,会造成工厂负担过重、效率变低,且不利于工厂的管理。所以,简单工厂模式适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象不需要关心。
举例
以计算机专业的学生课程为例,计算机专业的学生要学习Java课程。我们先定义Course接口:

public interface Course {
    void getCourse();
}

创建一个Java课程的实现类javaCourse类:

public class JavaCourse implements Course{
    @Override
    public void getCourse() {
        System.out.println("Java课程");
    }
}

客户端调用代码:

    public static void main(String[] args) {
        Course course = new JavaCourse();
        course.getCourse();
    }

在上面的代码中,父类Course指向子类JavaCourse的引用,应用层代码需要依赖JavaCourse。如果业务要进行扩展,学生要学习python、前端、大数据等课程,那么客户端的依赖就会变得越来越臃肿。因此,我们要想办法把这种依赖减弱,把创建细节隐藏起来。虽然在目前的代码中,创建对象的过程并不复杂,但从代码设计的角度来讲不易于扩展。现在,我们用简单工厂模式对代码进行优化。增加课程类PythonCourse:

public class PythonCourse implements Course {
    @Override
    public void getCourse() {
        System.out.println("Python课程");
    }
}

创建工厂类CourseFactory:

public class CourseFactory {
    public static Course create(String name){
        if("java".equals(name)){
            return new JavaCourse();
        } else if("python".equals(name)){
            return new PythonCourse();
        } else{
            return null;
        }
    }
}

修改客户端调用代码如下:

    public static void main(String[] args) {
        JavaCourse course = (JavaCourse) CourseFactory.create("java");
    }

可以明显的看出,客户端的调用变简单了,只需要去向工厂去索求,而不需要自己实现创建的细节。但是如果未来还开设了其它课程,我们还需要根据要求来修改代码逻辑,不符合开闭原则,因此我们可以用反射技术继续优化我们的程序,这里就不再赘述。
简单工厂模式也有缺点:工厂类的职责相对过重,不易与扩展过于复杂的产品结构,只适用于工厂类负责创建的对象较少的场景。

二、工厂方法模式

工厂方法模式是指定义一个创建对象的接口,让这个接口的实现类负责创建具体的对象,工厂方法模式是简单工厂模式的进一步抽象和推广,它让类的实例化推迟到子类中进行。工厂方法模式使用了多态性,即保持了简单工厂模式的优点,又克服了它的缺点。在工厂方法模式中,用户只需要关心所需产品对应的工厂,无需关心创建细节,而且加入新的产品时符合开闭原则。
工厂方法模式主要解决了产品的扩展问题。在简单工厂模式中,随着产品链的丰富,如果每个课程的创建逻辑有区别,则工厂的职责会变得越来越多,有点像万能工厂,不便于维护。根据单一职责原则,我们将只能继续拆分,专门的工厂干专门的事。我们令Java课程由Java工厂创建,Python课程由Python工厂创建,对工厂本身也做一个抽象。来看代码,先创建CourseFactory接口:

public interface CourseFactory {
    Course create();
}

再分别创建子工厂,JavaCourseFactory类的代码如下:

public class JavaCourseFactory implements CourseFactory{
    @Override
    public Course create() {
        return new JavaCourse();
    }
}

PythonCourseFactory类的代码如下:

public class PythonCourseFactory implements CourseFactory{
    @Override
    public Course create() {
        return new PythonCourse();
    }
}

测试代码:

    public static void main(String[] args) {
        CourseFactory factory = new JavaCourseFactory();
        Course course = factory.create();
        course.getCourse();
        
        factory = new PythonCourseFactory();
        course = factory.create();
        course.getCourse();
    }

工厂方法模式适用于以下场景:

  1. 创建对象需要大量重复的代码
  2. 客户端(应用层)不依赖于产品类实例如何被创建、如何被实现等
  3. 一个类通过其子类来指定创建哪个对象

工厂方法模式也有缺点:

  1. 类的个数容易过多,增加复杂度
  2. 增加了系统的抽象性和理解难度
  3. 一个具体工厂只能创建一个具体的产品,虽然说解决了对工厂方法内的修改关闭,如果换一个产品的话也是需要修改具体的产品类。

三、抽象工厂模式

抽象工厂模式是指提供一个创建一系列相关或相互依赖的接口,无需指定它们的具体类。客户端(应用层)不依赖于产品类实例如何被创建、何如被实现等细节,强调的是一些列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码,需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
在了解抽象工厂模式之前,我们先要了解一下产品组的概念:
产品族是指位于不同产品等级结构中,功能相关联的产品组成的家族。一般是位于不同的等级结构中的相同位置上。
仍以课程为例,现在学校有了新的标准,学生不仅可以获取到课程,还可以获取到图书资源。如果使用工厂方法模式,
在这里插入图片描述
如图所示,每个产品都要对应一个工厂。这本都是一个课程系列的产品,却要分成两个工厂来生产,这显然是没有必要的操作。
如果我们使用抽象工厂模式呢?
在这里插入图片描述
可以看出,一系列的产品只需要一个工厂去生产,更加符合我们的要求,减少了程序的负担。
Course接口如下:

public interface Course {
    void getCourse();
}

Book代码如下:

public interface Book {
    void getBook();
}

然后创建一个抽象工厂类CourseFactory:

public interface CourseFactory {
    Course createCourse();
    Book createBook();
}

接下来创建Java产品族的Java课程类javaCourse:

public class JavaCourse implements Course{
    @Override
    public void getCourse() {
        System.out.println("Java Course");
    }
}

扩展产品等级Java图书资源类JavaBook:

public class JavaBook implements Book{
    @Override
    public void getBook() {
        System.out.println("Java Book");
    }
}

创建Java产品族的具体工厂JavaCourseFactory:

public class JavaCourseFactory implements CourseFactory{
    @Override
    public Course createCourse() {
        return new JavaCourse();
    }

    @Override
    public Book createBook() {
        return new JavaBook();
    }
}

然后创建Python产品的Python课程类PythonCourse:

public class PythonCourse implements Course{
    @Override
    public void getCourse() {
        System.out.println("Python Course");
    }
}

扩展产品等级Python图书资源类PythonBook:

public class PythonBook implements Book{
    @Override
    public void getBook() {
        System.out.println("Python Book");
    }
}

创建Python产品族的具体工厂PythonCourseFactory:

public class PythonCourseFactory implements CourseFactory{
    @Override
    public Course createCourse() {
        return new PythonCourse();
    }

    @Override
    public Book createBook() {
        return new JavaBook();
    }
}

调用代码:

    public static void main(String[] args) {
        JavaCourseFactory factory = new JavaCourseFactory();
        factory.createCourse().getCourse();
        factory.createBook().getBook();
    }

上面的代码完整地描述了两个产品族:Java课程和Python课程,也描述了两个产品等级:课程资源和图书资源。抽象工厂模式非常完美清晰地描述了这样一层复杂的关系。但是,不知道大家有没有发现,如果我们再继续扩展产品等级,将源码Source也加入课程,那么我们的代码从抽象工厂到具体都要全部调整,很显然不符合开闭原则,由此可知抽象工厂模式也有缺点的:

  1. 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
  2. 增加了系统的抽象性和理解难度。

总结

从上文来看,工厂模式好像也没有所说的那么晦涩难懂,从本文的角度来看确实如此。但是实际上,我认为工厂模式还是比较复杂的。在本文中,介绍了每种工厂模式的优缺点,那么在现实开发中,如何做到“取其精华,舍弃糟粕”呢?怎么才能做到像SpringIOC容器一样,功能强大且使用便捷呢?
在实际应用中,我们千万不能“犯强迫症”甚至“有洁癖”。在实际需求中,产品等级结构升级是非常正常的一件事情。只要不频繁升级,根据实际情况可以不遵循开闭原则。代码每半年升级一次或者每年升级一次又有何不可呢?我们要知道,原则可以帮我们较少不必要的麻烦,但必要的更新与升级缺一不可。

文章参考于《Spring5核心原理与30个类手写实战》谭勇德 著

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-18 12:34:18  更:2021-08-18 12:35:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 3:43:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码