Spring中常用的设计模式——工厂模式
一、简单工厂模式
简单工厂模式也被称为静态工厂模式,它是指由一个工厂对象决定创建哪一种产品的实例。
简单举个例子,在原始社会,我们需要自给自足。在工业革命之后,世界上出现了各种各样的代工厂、流水线,人们只需要买来需要的产品,并且知道如何使用就行了。那么简单工厂模式也是如此,它可以将产品的使用和生产完全分开,客户端只需要知道需要什么产品,如何来使用产品的就可以了,而具体的产品生产任务由具体的工厂类来实现。
在现实的工厂中,如果大量的、多种类型的产品都在一个工厂生产,会造成工厂负担过重、效率变低,且不利于工厂的管理。所以,简单工厂模式适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象不需要关心。
举例
以计算机专业的学生课程为例,计算机专业的学生要学习Java课程。我们先定义Course接口:
public interface Course {void getCourse();
}
创建一个Java课程的实现类javaCourse类:
public class JavaCourse implements Course{@Overridepublic 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 {@Overridepublic 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{@Overridepublic Course create() {return new JavaCourse();}
}
PythonCourseFactory类的代码如下:
public class PythonCourseFactory implements CourseFactory{@Overridepublic 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();}
工厂方法模式适用于以下场景:
- 创建对象需要大量重复的代码
- 客户端(应用层)不依赖于产品类实例如何被创建、如何被实现等
- 一个类通过其子类来指定创建哪个对象
工厂方法模式也有缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
- 一个具体工厂只能创建一个具体的产品,虽然说解决了对工厂方法内的修改关闭,如果换一个产品的话也是需要修改具体的产品类。
三、抽象工厂模式
抽象工厂模式是指提供一个创建一系列相关或相互依赖的接口,无需指定它们的具体类。客户端(应用层)不依赖于产品类实例如何被创建、何如被实现等细节,强调的是一些列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码,需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
在了解抽象工厂模式之前,我们先要了解一下产品组的概念:
产品族是指位于不同产品等级结构中,功能相关联的产品组成的家族。一般是位于不同的等级结构中的相同位置上。
仍以课程为例,现在学校有了新的标准,学生不仅可以获取到课程,还可以获取到图书资源。如果使用工厂方法模式,
如图所示,每个产品都要对应一个工厂。这本都是一个课程系列的产品,却要分成两个工厂来生产,这显然是没有必要的操作。
如果我们使用抽象工厂模式呢?
可以看出,一系列的产品只需要一个工厂去生产,更加符合我们的要求,减少了程序的负担。
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{@Overridepublic void getCourse() {System.out.println("Java Course");}
}
扩展产品等级Java图书资源类JavaBook:
public class JavaBook implements Book{@Overridepublic void getBook() {System.out.println("Java Book");}
}
创建Java产品族的具体工厂JavaCourseFactory:
public class JavaCourseFactory implements CourseFactory{@Overridepublic Course createCourse() {return new JavaCourse();}@Overridepublic Book createBook() {return new JavaBook();}
}
然后创建Python产品的Python课程类PythonCourse:
public class PythonCourse implements Course{@Overridepublic void getCourse() {System.out.println("Python Course");}
}
扩展产品等级Python图书资源类PythonBook:
public class PythonBook implements Book{@Overridepublic void getBook() {System.out.println("Python Book");}
}
创建Python产品族的具体工厂PythonCourseFactory:
public class PythonCourseFactory implements CourseFactory{@Overridepublic Course createCourse() {return new PythonCourse();}@Overridepublic Book createBook() {return new JavaBook();}
}
调用代码:
public static void main(String[] args) {JavaCourseFactory factory = new JavaCourseFactory();factory.createCourse().getCourse();factory.createBook().getBook();}
上面的代码完整地描述了两个产品族:Java课程和Python课程,也描述了两个产品等级:课程资源和图书资源。抽象工厂模式非常完美清晰地描述了这样一层复杂的关系。但是,不知道大家有没有发现,如果我们再继续扩展产品等级,将源码Source也加入课程,那么我们的代码从抽象工厂到具体都要全部调整,很显然不符合开闭原则,由此可知抽象工厂模式也有缺点的:
- 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
- 增加了系统的抽象性和理解难度。
总结
从上文来看,工厂模式好像也没有所说的那么晦涩难懂,从本文的角度来看确实如此。但是实际上,我认为工厂模式还是比较复杂的。在本文中,介绍了每种工厂模式的优缺点,那么在现实开发中,如何做到“取其精华,舍弃糟粕”呢?怎么才能做到像SpringIOC容器一样,功能强大且使用便捷呢?
在实际应用中,我们千万不能“犯强迫症”甚至“有洁癖”。在实际需求中,产品等级结构升级是非常正常的一件事情。只要不频繁升级,根据实际情况可以不遵循开闭原则。代码每半年升级一次或者每年升级一次又有何不可呢?我们要知道,原则可以帮我们较少不必要的麻烦,但必要的更新与升级缺一不可。
文章参考于《Spring5核心原理与30个类手写实战》谭勇德 著
Spring中常用的设计模式——工厂模式相关推荐
- 学习笔记【Spring中常用的设计模式】
文章目录 简介 一. Spring用到的设计模式类别 1. 创建型模式 2. 结构性模式 3. 行为型模式 二. 设计模式详解 1. 工厂模式 1.1 简单工厂模式 1.2 工厂方法模式 1.3 抽象 ...
- 六大常用软件设计模式—工厂模式
当当当当~~~~欢迎大家阅读,今天我们学习六大常用软件设计模式中的工厂模式 工厂模式 (Factory Pattern) 一:工厂模式的定义 就是建立一个工厂类,对实现了同一接口的一些类 ...
- Spring 中常用的设计模式对比
各设计模式对比及编程思想总结 设计模式 一句话归纳 举例 工厂模式(Factory) 只对结果负责,封装创建过程. BeanFactory.Calender 单例模式(Singleton) 保证独一无 ...
- Spring中常见的设计模式
Spring中常见的设计模式 1.Java设计模式 设计模式(Design Pattern)是解决特定问题的一系列套路.它不是语法规定,而是一套用来提高代码可复用性.可维护性.可读性.稳健性以及安全性 ...
- Spring中的部分设计模式
目录: 目录 设计模式在应用中遵循六大原则: a.开闭原则 b.里氏代换原则 c.依赖倒转原则 d.接口隔离原则 e.迪米特法则(最少知道原则) f.合成复用原则 设计模式之间的关系图 1.工厂模式( ...
- java设计模式工厂模式_Java中的工厂设计模式
java设计模式工厂模式 Welcome to the Factory Design Pattern in Java tutorial. Factory Pattern is one of the C ...
- java设计模式工厂模式_Java中的复合设计模式
java设计模式工厂模式 Composite pattern is one of the Structural design pattern. Composite design pattern is ...
- java设计模式工厂模式_Java中的桥梁设计模式
java设计模式工厂模式 Today we will look into Bridge Design Pattern in java. When we have interface hierarchi ...
- java设计模式工厂模式_Java中的外观设计模式
java设计模式工厂模式 Facade Design Pattern is one of the Structural design patterns (such as Adapter pattern ...
最新文章
- 2015.11.11
- 设置更改root密码(远程,本地)、连接mysql、mysql常用命令
- 第十六届智能车竞赛线上全国总决赛远程组委会监督腾讯会议
- 中兴通讯与寒武纪合作 加速5G时代边缘智能
- 宝塔无法安装php memcached,宝塔面板安装Memcached缓存加速wordpress
- SAP License:SAP合同类型的使用
- Matlab读取图像数据并写入TXT
- 针对使用ng-lint,eslint,tslint,生成报告以及环境安装的一系列问题及解决办法
- 《微积分:极限与连续》——连续的两种定义
- ASP.NET的六大对象介绍
- nodejs开发环境安装-连载【1】-企业级系统开发实战连载系列 -技术栈 :vue、element-ui、qt、c++、sqlite
- 牵一只蜗牛去散步……
- [小作品]小小梦想初级物理摸拟系统
- 利用MATLAB求解积分
- 你若运行,便是晴天!
- matlab直观数据处理,霍尔效应实验的MATLAB数据处理
- Visual Studio 2015 Bowser Link的功能不停的向服务端发送请求
- matlab 怎么使用mathtype,教你怎样在Authorea里面使用MathType
- 微型计算机2019年度金奖产品,【MC 2019年度评选获奖产品展播】华硕/ROG DIY精品斩获多个大奖...
- 拆长虹iho3000_(CA版)四川长虹iho-3000t晶晨s905l-b刷全网通系统教程可救砖头
热门文章
- 为Linux部署红旗紫光输入法
- 毕业设计-基于深度学习的数字病理图像分割
- 物联网卡系统php,物联网卡开发文案
- 移动端浏览器触摸事件@touchstart=“touchstart“ @touchend=“touchend“ @touchmove=“touchmove“
- 移动web开发 手机输入框弹出的问题
- MATLAB求解方程和多元方程组
- 贴吧顶贴php脚步,【技术贴安卓按键精灵】贴吧顶贴脚本源码分享
- 推荐一款开源的音乐下载神器,8个平台VIP任你选
- 游戏中的答题活动也可以通过远程代答么?
- 【开发工具】【JTAG】JTAG基础【一】