工厂模式 五种写法总结
一概述:
属于创建型设计模式,需要生成的对象叫做产品 ,生成对象的地方叫做工厂 。
使用场景:
在任何需要生成复杂对象的地方,都可以使用工厂方法模式。
直接用new可以完成的不需要用工厂模式
个人理解,重点就是这个复杂 (构造函数有很多参数)和 是否可以 直接用new。(不理解这句话的话,看完一圈例子就理解了)
下面逐个介绍我所知道的各种工厂模式以及它们的特点,使用场景,并尽可能的找出JDK SDK里它们的身影。
二 简单(静态)工厂:
一个栗子:
我喜欢吃面条,抽象一个面条基类,(接口也可以),这是产品的抽象类。
public abstract class INoodles {/*** 描述每种面条啥样的*/public abstract void desc();
}
- 1
- 2
- 3
- 4
- 5
- 6
先来一份兰州拉面(具体的产品类):
public class LzNoodles extends INoodles {@Overridepublic void desc() {System.out.println("兰州拉面 上海的好贵 家里才5 6块钱一碗");}
}
- 1
- 2
- 3
- 4
- 5
- 6
程序员加班必备也要吃泡面(具体的产品类):
public class PaoNoodles extends INoodles {@Overridepublic void desc() {System.out.println("泡面好吃 可不要贪杯");}
}
- 1
- 2
- 3
- 4
- 5
- 6
还有我最爱吃的家乡的干扣面(具体的产品类):
public class GankouNoodles extends INoodles {@Overridepublic void desc() {System.out.println("还是家里的干扣面好吃 6块一碗");}
}
- 1
- 2
- 3
- 4
- 5
- 6
准备工作做完了,我们来到一家“简单面馆”(简单工厂类),菜单如下:
public class SimpleNoodlesFactory {public static final int TYPE_LZ = 1;//兰州拉面public static final int TYPE_PM = 2;//泡面public static final int TYPE_GK = 3;//干扣面public static INoodles createNoodles(int type) {switch (type) {case TYPE_LZ:return new LzNoodles();case TYPE_PM:return new PaoNoodles();case TYPE_GK:default:return new GankouNoodles();}}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
简单面馆就提供三种面条(产品),你说你要啥,他就给你啥。这里我点了一份干扣面:
/*** 简单工厂模式*/INoodles noodles = SimpleNoodlesFactory.createNoodles(SimpleNoodlesFactory.TYPE_GK);noodles.desc();
- 1
- 2
- 3
- 4
- 5
输出:
还是家里的干扣面好吃 6块一碗
- 1
特点
1 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
2 create()方法通常是静态的,所以也称之为静态工厂。
缺点
1 扩展性差(我想增加一种面条,除了新增一个面条产品类,还需要修改工厂类方法)
2 不同的产品需要不同额外参数的时候 不支持。
三 另一种简单工厂(反射):
利用反射Class.forName(clz.getName()).newInstance()
实现的简单工厂:
public class StaticNoodlesFactory {/*** 传入Class实例化面条产品类** @param clz* @param <T>* @return*/public static <T extends INoodles> T createNoodles(Class<T> clz) {T result = null;try {result = (T) Class.forName(clz.getName()).newInstance();} catch (Exception e) {e.printStackTrace();}return result;}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
点菜时:
/*** 另一种简单工厂* 利用Class.forName(clz.getName()).newInstance()*/System.out.println("=====另一种简单工厂利用Class.forName(clz.getName()).newInstance()======" +"\n个人觉得不好,因为这样和简单的new一个对象一样,工厂方法应该用于复杂对象的初始化" +"\n 这样像为了工厂而工厂");//兰州拉面INoodles lz = StaticNoodlesFactory.createNoodles(LzNoodles.class);lz.desc();//泡面INoodles pm = StaticNoodlesFactory.createNoodles(PaoNoodles.class);pm.desc();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
输出:
=====另一种简单工厂利用Class.forName(clz.getName()).newInstance()======
个人觉得不好,因为这样和简单的new一个对象一样,工厂方法应该用于复杂对象的初始化这样像为了工厂而工厂
兰州拉面 上海的好贵 家里才5 6块钱一碗
泡面好吃 可不要贪杯
- 1
- 2
- 3
- 4
- 5
特点
1 它也是一个具体的类,非接口 抽象类。但它的create()方法,是利用反射机制生成对象返回,好处是增加一种产品时,不需要修改create()的代码。
缺点
这种写法粗看牛逼,细想之下,不谈reflection的效率还有以下问题:
1 个人觉得不好,因为Class.forName(clz.getName()).newInstance()调用的是无参构造函数生成对象,它和new Object()是一样的性质,而工厂方法应该用于复杂对象的初始化 ,当需要调用有参的构造函数时便无能为力了,这样像为了工厂而工厂。
2 不同的产品需要不同额外参数的时候 不支持。
四 多方法工厂(常用)
使用方法二 三实现的工厂,都有一个缺点:不同的产品需要不同额外参数的时候 不支持。
而且如果使用时传递的type、Class出错,将不能得到正确的对象,容错率不高。
而多方法的工厂模式为不同产品,提供不同的生产方法,使用时 需要哪种产品就调用该种产品的方法,使用方便、容错率高。
工厂如下:
public class MulWayNoodlesFactory {/*** 模仿Executors 类* 生产泡面** @return*/public static INoodles createPm() {return new PaoNoodles();}/*** 模仿Executors 类* 生产兰州拉面** @return*/public static INoodles createLz() {return new LzNoodles();}/*** 模仿Executors 类* 生产干扣面** @return*/public static INoodles createGk() {return new GankouNoodles();}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
使用时:
/*** 多方法静态工厂(模仿Executor类)*/System.out.println("==============================模仿Executor类==============================" +"\n 这种我比较青睐,增加一个新面条,只要去增加一个static方法即可,也不修改原方法逻辑");INoodles lz2 = MulWayNoodlesFactory.createLz();lz2.desc();INoodles gk2 = MulWayNoodlesFactory.createGk();gk2.desc();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
输出:
==============================模仿Executor类==============================
这种我比较青睐,增加一个新面条,只要去增加一个static方法即可,也不修改原方法逻辑
兰州拉面 上海的好贵 家里才5 6块钱一碗
还是家里的干扣面好吃 6块一碗
- 1
- 2
- 3
- 4
源码撑腰环节
查看java源码:java.util.concurrent.Executors
类便是一个生成Executor
的工厂 ,其采用的便是 多方法静态工厂模式:
例如ThreadPoolExecutor
类构造方法有5个参数,其中三个参数写法固定,前两个参数可配置,如下写。
public static ExecutorService newFixedThreadPool(int nThreads) {return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}
- 1
- 2
- 3
- 4
- 5
又如JDK想增加创建ForkJoinPool
类的方法了,只想配置parallelism
参数,便在类里增加一个如下的方法:
public static ExecutorService newWorkStealingPool(int parallelism) {return new ForkJoinPool(parallelism,ForkJoinPool.defaultForkJoinWorkerThreadFactory,null, true);}
- 1
- 2
- 3
- 4
- 5
- 6
这个例子可以感受到工厂方法的魅力了吧:方便创建 同种类型的 复杂参数 对象。
五 普通工厂
普通工厂就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层+具体的工厂子类层。(一般->特殊)
面条工厂(抽象工厂类),作用就是生产面条:
public abstract class NoodlesFactory {public abstract INoodles create();
}
- 1
- 2
- 3
兰州拉面工厂 (具体工厂子类):
public class LzFactory extends NoodlesFactory {@Overridepublic INoodles create() {return new LzNoodles();}
}
- 1
- 2
- 3
- 4
- 5
- 6
泡面工厂 (具体工厂子类):
public class PaoFactory extends NoodlesFactory {@Overridepublic INoodles create() {return new PaoNoodles();}
}
- 1
- 2
- 3
- 4
- 5
- 6
最爱的干扣面工厂 (具体工厂子类):
public class GankouFactory extends NoodlesFactory {@Overridepublic INoodles create() {return new GankouNoodles();}
}
- 1
- 2
- 3
- 4
- 5
- 6
使用时:
/*** 普通工厂方法:*/System.out.println("===========================普通工厂方法==============================" +"\n 这种要多写一个类,不过更面向对象吧 = = ,实际中我更倾向于使用【模仿Executor类】的方式");NoodlesFactory factory1 = new GankouFactory();INoodles gk3 = factory1.create();gk3.desc();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
输出:
===========================普通工厂方法==============================
这种要多写一个类,不过更面向对象吧 = = ,实际中我更倾向于使用【模仿Executor类】的方式
还是家里的干扣面好吃 6块一碗
- 1
- 2
- 3
普通工厂与简单工厂模式的区别:
可以看出,普通工厂模式特点:不仅仅做出来的产品要抽象, 工厂也应该需要抽象。
工厂方法使一个产品类的实例化延迟到其具体工厂子类.
工厂方法的好处就是更拥抱变化。当需求变化,只需要增删相应的类,不需要修改已有的类。
而简单工厂需要修改工厂类的create()方法,多方法静态工厂模式需要增加一个静态方法。
缺点:
引入抽象工厂层后,每次新增一个具体产品类,也要同时新增一个具体工厂类,所以我更青睐 多方法静态工厂。
六 抽象工厂:
以上介绍的工厂都是单产品系的。抽象工厂是多产品系 (貌似也有产品家族的说法)。
举个例子来说,每个店(工厂)不仅仅卖面条,还提供饮料卖。
提供饮料卖,饮料是产品,先抽象一个产品类,饮料:
public abstract class IDrinks {/*** 描述每种饮料多少钱*/public abstract void prices();
}
- 1
- 2
- 3
- 4
- 5
- 6
然后实现两个具体产品类:
可乐:
public class ColaDrinks extends IDrinks {@Overridepublic void prices() {System.out.println("可乐三块五");}
}
- 1
- 2
- 3
- 4
- 5
- 6
屌丝还是多喝水吧:
public class WaterDrinks extends IDrinks {@Overridepublic void prices() {System.out.println("和我一样的穷鬼都喝水,不要钱~!");}
}
- 1
- 2
- 3
- 4
- 5
- 6
抽象饭店,无外乎吃喝(抽象工厂类):
public abstract class AbstractFoodFactory {/*** 生产面条** @return*/public abstract INoodles createNoodles();/*** 生产饮料*/public abstract IDrinks createDrinks();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
兰州大酒店(具体工厂类):
public class LzlmFoodFactory extends AbstractFoodFactory {@Overridepublic INoodles createNoodles() {return new LzNoodles();//卖兰州拉面}@Overridepublic IDrinks createDrinks() {return new WaterDrinks();//卖水}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
KFC(具体工厂类):
public class KFCFoodFactory extends AbstractFoodFactory {@Overridepublic INoodles createNoodles() {return new PaoNoodles();//KFC居然卖泡面}@Overridepublic IDrinks createDrinks() {return new ColaDrinks();//卖可乐}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
使用:
/*** 抽象工厂方法:*/System.out.println("==============================抽象方法==============================" +"\n 老实说,以我这一年的水平我体会不到抽象工厂有何巨大优势,所以在我这里我没有想到很好的使用场景。希望以后在慢慢体会吧。");AbstractFoodFactory abstractFoodFactory1 = new KFCFoodFactory();abstractFoodFactory1.createDrinks().prices();abstractFoodFactory1.createNoodles().desc();abstractFoodFactory1= new LzlmFoodFactory();abstractFoodFactory1.createDrinks().prices();abstractFoodFactory1.createNoodles().desc();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
输出:
==============================抽象方法==============================
老实说,以我这一年的水平我体会不到抽象工厂有何巨大优势,所以在我这里我没有想到很好的使用场景。希望以后在慢慢体会吧。
可乐三块五
泡面好吃 可不要贪杯
和我一样的穷鬼都喝水,不要钱~!
兰州拉面 上海的好贵 家里才5 6块钱一碗
- 1
- 2
- 3
- 4
- 5
- 6
小结:
将工厂也抽象了,在使用时,工厂和产品都是面向接口编程,OO(面向对象)的不得了。
缺点
但是将工厂也抽象后,有个显著问题,就是类爆炸了。而且每次拓展新产品种类,例如不仅卖吃卖喝,我还想卖睡,提供床位服务,这需要修改抽象工厂类,因此所有的具体工厂子类,都被牵连,需要同步被修改。
老实说,以我这一年的水平我体会不到抽象工厂有何巨大优势,所以在我这里我没有想到很好的使用场景。希望以后在慢慢体会吧。如有您知道,希望不吝赐教。
七 个人总结和使用场景
一句话总结工厂模式:方便创建 同种产品类型的 复杂参数 对象
工厂模式重点就是适用于 构建同产品类型(同一个接口 基类)的不同对象时,这些对象new很复杂,需要很多的参数,而这些参数中大部分都是固定的,so,懒惰的程序员便用工厂模式封装之。
(如果构建某个对象很复杂,需要很多参数,但这些参数大部分都是“不固定”的,应该使用Builder模式)
为了适应程序的扩展性,拥抱变化,便衍生出了 普通工厂、抽象工厂等模式。
[原文来源]:https://blog.csdn.net/zxt0601/article/details/52798423
工厂模式 五种写法总结相关推荐
- 设计模式(一) 工厂模式 五种写法总结
转载请标明出处: http://blog.csdn.net/zxt0601/article/details/52798423 本文出自:[张旭童的博客] 系列开篇瞎BB 设计模式相关的文章学习与总结, ...
- Kotlin中单利常用的五种写法
前言 单利模式是写代码过程中不可避免用到的,下面我总结一下单利常用的五种写法,话不多说了,来一起看看详细的介绍吧 加载类时创建单利 Java实现 public class Config{ privat ...
- 回字有四种写法,那你知道单例有五种写法吗
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达今日推荐:2020年7月程序员工资统计,平均14357元,又跌了,扎心个人原创100W+访问量博客:点击前往,查看更多 转自 ...
- 基于JS实现回到页面顶部的五种写法(从实现到增强)
为什么80%的码农都做不了架构师?>>> 写法 [1]锚点 使用锚点链接是一种简单的返回顶部的功能实现.该实现主要在页面顶部放置一个指定名称的锚点链接,然后在页面下方放置一个返 ...
- js浏览器回到顶部方法_基于JS实现回到页面顶部的五种写法(从实现到增强)
写法 [1]锚点 使用锚点链接是一种简单的返回顶部的功能实现.该实现主要在页面顶部放置一个指定名称的锚点链接,然后在页面下方放置一个返回到该锚点的链接,用户点击该链接即可返回到该锚点所在的顶部位置 [ ...
- 【转】回字有四种写法,那你知道单例有五种写法吗
目录导航 基本介绍 写法介绍 饿汉式 懒汉式 双重检测 内部类 枚举 总结 基本介绍 单例模式(Singleton)应该是大家接触的第一个设计模式,其写法相较于其他的设计模式来说并不复杂,核心理念也非 ...
- Unity/C# 舍入的五种写法
舍入的五种写法 0. 简介 舍入是一个数学概念,一种修约规则. 在日常的生活中,我们为了精简格式,记忆方便,常常会使用四舍五入的方法来去掉零头或凑个整数来解决此类问题. 在游戏中开发中,舍入也是数值计 ...
- java 工厂模式的写法_java工厂模式三种详解
工厂方法模式(Factory Method) 工厂方法模式分为三种: 1.普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建.首先看下关系图: 举例如下:(我们举一个发送邮件和短 ...
- 事件处理之二:点击事件监听器的五种写法
首选方法二! 方法一:写一个内部类,在类中实现点击事件 1.在父类中调用点击事件 bt_dail.setOnClickListener(new MyButtonListener()); 2.创建内部类 ...
最新文章
- Google 神秘 Fuchsia OS 的开源线索
- 查看某段代码或语句的被调用路径的方法小结
- 服务器操作系统策略,Windows操作系统组策略应用全攻略(2)服务器教程 -电脑资料...
- 2.2 CPU 上下文切换是什么意思?(下)
- 解读STM32标准库的程序架构 - 以GPIO操作为例
- centos7创建asm磁盘_Oracle ASM 磁盘组基础知识整理(收藏版)
- LeetCode 673. 最长递增子序列的个数(DP)
- HDU 4927 大数运算
- 南开大学计算机考研2019分数线,2019年南开大学考研复试分数线已公布
- java游戏细菌_细菌Bacteria
- 毕啸南专栏 | 对话旷视CEO印奇:AI产业2018年将迎来转折
- 37.django基础概念
- Excel怎么随机生成偶数
- CAN总线物理值与原始值
- 一个由两个长的如此相像的字引起的问题
- web server+app server
- Java 入门之1:浅谈Java的最基本概念及JDK、JRE、JVM之间的关系和区别
- 地表水水质监测数据/已去重/含坐标
- html5图片平铺的代码,jQuery图片平铺效果制作网页背景图片平铺代码
- 微博爬虫及舆情分析-4.用户舆情分析
热门文章
- cadence导入dxf文件_Allegro PCB导入DXF文件详解
- 手机电路板文件_ORICO移动硬盘盒玩出新花样,变身手机备份宝
- 黑白液晶COG与COB的区别
- win10安装Microsoft Office 2016(64位)提示已安装Microsoft Office 2016(32位)
- Lambda表达式到底是什么?——简单了解Lambda表达式
- 网易云短信接口调入(java)
- 移动硬盘\U盘在使用过程中0x80070570 文件或目录损坏且无法读取 CHKDSK 修复方法
- 图片生成 php源码_php图像验证码生成代码
- 数据结构学习:哈希表
- 【原创】我所认识的银行业务之旅(账务篇)