一文学会如何使用工厂模式
工厂模式属于创建型设计模式,由简而繁可以分为简单工厂模式、工厂模式以及抽象工厂模式,虽然代码相对来说逐渐复杂,但是对于调用者而言却是越来越简单。
简单工厂模式
简单工厂模式是指由一个工厂对象决定创建出哪一种产品类的实例,但它不属于GOF23种设计模式。简单工厂适用于工厂类负责创建的对象较少的情况,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。
接下来我们直接以代码为例,这里我们按照课程来处理。
因为我们可能由多门课程,所以我们需要一个课程的接口。
public interface ICourse {void record();}
这个时候我们来创建一个JAVA课程实现课程接口。
public class JavaCourse implements ICourse{@Overridepublic void record() {System.out.println("JAVA学习");}
}
调用课程方法也很简单,直接实例化即可。
public class Main {public static void main(String[] args) {ICourse course = new JavaCourse();course.record();}
}
上面的代码,父类ICourse
指向子类JavaCourse
的引用,应用层代码需要依赖JavaCourse
,如果我们的课程越来越多,我们这里会增加很多课程代码,导致代码变得很臃肿,因此我们需要把这种依赖减弱,把创建的细节隐藏。我们先通过简单工厂模式来优化代码。
首先再次创建一个课程类。
public class PythonCourse implements ICourse{@Overridepublic void record() {System.out.println("PYTHON学习");}
}
然后创建工厂类,用来创建我们所需要的课程。
public class CourseFactory {public ICourse create(String name) {if ("java".equals(name)) {return new JavaCourse();} else if ("python".equals(name)) {return new PythonCourse();} else {return null;}}
}
这时候的客户端调用只需要传入课程名就可以获取对应实例。
public class Main {public static void main(String[] args) {ICourse course = new CourseFactory().create("java");course.record();}
}
从类图种我们可以看出现在的调用时简单了,但是随着业务的继续拓展,每次添加课程我们都需要修改代码,因此我们的代码还有优化的空间。
这里我们可以采用反射技术,根据传入的类名,我们直接反射出对应的实例。
public ICourse createByReflect(String className) {if (className == null) {return null;}try {return (ICourse) Class.forName(className).newInstance();} catch (Exception e) {e.printStackTrace();}return null;
}
修改客户端调用代码:
public class Main {public static void main(String[] args) {ICourse course = new CourseFactory().createByReflect("com.example.javadesign.factory.simplefactory.JavaCourse");course.record();}
}
优化之后,就算添加新的课程我们也不需要去修改代码了,但是我们传递的参数太过复杂,很容易搞错,同时还需要进行类型强转,所以我们还需要进行优化。
public ICourse createByClass(Class<? extends ICourse> clazz) {if (clazz == null) {return null;}try {return clazz.newInstance();} catch (Exception e) {e.printStackTrace();}return null;
}
修改调用方法:
public class Main {public static void main(String[] args) {ICourse course = new CourseFactory().createByClass(JavaCourse.class);course.record();}
}
现在我们再看这个创建方法是不是就很好了,我们只需要传递对应的类型就可以直接创建实例了,简单快捷。
简单工厂模式在JDK源码种用的也很多,比如Calendar
类,我们来看他获取实例的方法。Calendar.getInstance();
public static Calendar getInstance()
{return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}private static Calendar createCalendar(TimeZone zone,Locale aLocale){CalendarProvider provider =LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale).getCalendarProvider();if (provider != null) {try {return provider.getInstance(zone, aLocale);} catch (IllegalArgumentException iae) {// fall back to the default instantiation}}Calendar cal = null;if (aLocale.hasExtensions()) {String caltype = aLocale.getUnicodeLocaleType("ca");if (caltype != null) {switch (caltype) {case "buddhist":cal = new BuddhistCalendar(zone, aLocale);break;case "japanese":cal = new JapaneseImperialCalendar(zone, aLocale);break;case "gregory":cal = new GregorianCalendar(zone, aLocale);break;}}}if (cal == null) {// If no known calendar type is explicitly specified,// perform the traditional way to create a Calendar:// create a BuddhistCalendar for th_TH locale,// a JapaneseImperialCalendar for ja_JP_JP locale, or// a GregorianCalendar for any other locales.// NOTE: The language, country and variant strings are interned.if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {cal = new BuddhistCalendar(zone, aLocale);} else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"&& aLocale.getCountry() == "JP") {cal = new JapaneseImperialCalendar(zone, aLocale);} else {cal = new GregorianCalendar(zone, aLocale);}}return cal;}
还有大家经常使用的logback
里面也有多个重载的方法。
总结
优点
只需要传入一个正确参数即可获取所需对象,无需知道创建的细节。
缺点
工厂类的职责相对过重,增加新的产品时需要修改工厂类的判断逻辑,违背开闭原则;不易于拓展过于复杂的产品结构
工厂模式
工厂方法模式是指定义一个创建对象的接口,让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。在工厂方法模式中用户只需要关心所需产品对应的工厂,无需关心创建细节,而且加入新的产品符合开闭原则。
工厂模式主要解决产品拓展的问题,在简单工厂中,随着产品链的丰富如果每个产品的创建逻辑有区别的话,工厂的职责会变得越来越多,有点像万能工厂,但不便于维护。根据单一职责原则我们需要将其职能进行拆分,专人干专事。
代码如下所示:我们首先创建工厂接口:
public interface ICourseFactory {public ICourse create();}
然后创建Java工厂:
public class JavaCourseFactory implements ICourseFactory{@Overridepublic ICourse create() {return new JavaCourse();}
}
这个时候我们创建实例的时候只需要通过指定工厂就可以直接获取实例了。
public class Main {public static void main(String[] args) {ICourseFactory courseFactory= new JavaCourseFactory();ICourse course = courseFactory.create();course.record();}
}
工厂方法适用于以下场景:
- 创建对象需要大量重复的代码
- 客户端不依赖于产品类如何被创建,实现等细节。
- 一个类通过其子类来指定创建哪个对象。
但也有相关缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
抽象工厂模式
抽象工厂模式是指提供一个创建一系列相关或相互依赖对象的接口,无需指定他们具体的类。客户端不依赖于产品类实例如何被创建、实现等细节。需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
可能说的太抽象,我们按照一个案例来看。
产品:课程
产品族:Java课程
产品等级:课程视频、课程笔记
以课程为例,我们上网课的时候需要看视频,同时可能老师还会提供相关的笔记。相当于现在的业务变为一个课程不单纯是一个课程信息,需要同时包含视频,笔记才算一个完整的课程。我们之前只有一个课程接口,现在还需要新增视频以及笔记接口。
public interface INote {void edit();}
public interface IVideo {void play();}
然后实现两个产品等级:视频以及笔记:
public class JavaVideo implements IVideo{@Overridepublic void play() {}
}
public class JavaNode implements INote{@Overridepublic void edit() {}
}
这个时候我们来创建一个抽象工厂CourseFactory
类,我们也可以使用接口来实现,但是使用抽象工厂我们可以写一些公有方法。
public abstract class CourseFactory {public void init(){System.out.println("初始化基础数据");}protected abstract INote createNote();protected abstract IVideo createVideo();}
创建Java产品族的具体工厂JavaCourseFactory
:
public class JavaCourseFactory extends CourseFactory{@Overrideprotected INote createNote() {super.init();return new JavaNode();}@Overrideprotected IVideo createVideo() {super.init();return new JavaVideo();}
}
调用:
public class Main {public static void main(String[] args) {CourseFactory factory = new JavaCourseFactory();factory.createNote().edit();factory.createVideo().play();}
}
上面的代码描述了产品族Java课程
,也描述了两个产品等级:视频和笔记。
抽象工厂非常完美清晰的描述这样一层复杂的关系。但是不知道大家有没有发现,如果我们继续扩展产品等级,比如加入作业,那么我们的抽象工厂从抽象工厂到具体工厂都需要全部调整,很显然这不符合开闭原则。因此抽象工厂的缺点也很明显:
- 增加了系统的抽象性和理解难度
- 规定了所有可能被创建的产品集合,产品族中拓展新的产品困难,需要修改抽象工厂的接口。
但是在实际应用中,产品等级结构升级时非常正常的,只要不是频繁升级,我们可以不遵守开闭原则。
项目地址
设计模式案例
一文学会如何使用工厂模式相关推荐
- 一文学透设计模式——抽象工厂模式
创建者模式 抽象工厂模式 概念 抽象工厂模式是围绕一个超级工厂创建其他工厂.该超级工厂又称为其他工厂的工厂.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这是很多地方对于抽象工厂 ...
- 【Spring】工厂模式解耦
问题: 程序的耦合 耦合:程序间的依赖关系 包括:类之间的依赖 方法之间的依赖 解耦:降低程序之间的耦合关系 实际开发:编译期不依赖,运行期才依赖 解耦思路: ...
- GOF23设计模式(创建型模式)工厂模式
目录: 一:工厂模式的核心本质 二:关于面向对象的六大基本原则 三:工厂模式的三大类详解(代码示例,详细分析) 首先,上咱本GOF23所有工厂模式的分类表格!!! 创建型模式 单例模式.工厂模式.抽象 ...
- 大话设计模式之简单的工厂模式
第一章:代码无错就是优-简单的工厂模式 先建立一个计算类Operation Operation.h文件 @interface Operation : NSObject@property(nonatom ...
- 设计模式之简单工厂模式
一.概述 工厂模式具体包括了简单工厂.工厂方法.抽象工厂,它们是按照从简单到复杂的顺序排列的,属于设计模式中的创建型,其中简单工厂并不属于GOF的23中模式. 但是它是理解其它的工厂模式的一个很好 ...
- 基础设计模式:单例模式+工厂模式+注册树模式
单例模式: 通过提供自身共享实例的访问,单例设计模式用于限制特定对象只能被创建一次. 使用场景: 一般数据库实例都会用单例模式 实现: 单例设计模式就是要一个类只能实例化一个对象. 要想让一个类只能实 ...
- 抽象工厂模式 java实例 tclhaier_Unity常用的设计模式_工厂模式系列之抽象工厂模式...
在工厂方法模式中,工厂只负责生产具体的产品,每一个具体的工厂对应着一个具体的产品,工厂方法也具有唯一性,如果有时候我们需要一个工厂方法提供多个产品而不是一个单一的产品,例如:海尔品牌不止生产海尔TV, ...
- getinstance方法详解_二、设计模式总览及工厂模式详解
二.架构师内功心法之设计模式 2.架构师内功心法之设计模式 2.1.课程目标 1.通过对本章内容的学习,了解设计模式的由来. 2.介绍设计模式能帮我们解决哪些问题. 3.剖析工厂模式的历史由来及应用场 ...
- java设计模式中不属于创建型模式_23种设计模式第二篇:java工厂模式定义:工厂模式是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式...
23种设计模式第二篇:java工厂模式 定义: 工厂模式是 Java 中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 工厂模式主要是为创建对象提供过渡接口, ...
- 编程模式 之美 -- 抽象工厂模式
文章目录 1. 解决问题 2. 应用场景 3. 实现如下: C++实现 C语言实现 4. 缺点 1. 解决问题 在工厂方法模式中,我们卖衣服.此时我们为每一种衣服创建不同的工厂,帽子有一个工厂专门创建 ...
最新文章
- 卡常神器——register 与 快速读入输出
- 5G NR上行控制信道PUCCH
- Javaweb练手项目
- linux buffer cache 过高_怎么理解内存中的Buffer和Cache?
- 【翻译】优秀网站的10个技巧
- android中打开地理位置,Android中获取地理位置经纬度
- div+css网页html成品学生作业包含10个html页面——动漫主题海贼王
- win7自带防火墙怎么关闭
- QChart入门教程-绘制正弦曲线
- Eclipse打开资源管理器
- 无心剑英译许巍《温暖》
- unix时间戳 为什么计算机时间要从1970年1月1日开始算起?
- 在Swift中使用dispatch_once单例模型
- asp新闻发布系统 html,构建你的网站新闻自动发布系统之一_asp实例
- Java mysql获取行数_java – MySQL查询获取球体中的行(X,Y,Z坐标)?
- 我的家计算机教学反思,我的家教学反思
- matlab程序模拟微信抢红包,微信红包算法MATLAB实现
- gradle 缓存的jar包仓库的目录在哪
- java并发编程实战(二)
- 初入职场|入门互联网产品经理