总的来说 , 设计模式可以分为三大类:创建型模式、结构型模式、行为型模式 。工厂模式分为简单工厂模式、工厂方法模式和抽象工厂模式 。一、设计模式的分类总的来说 , 设计模式可以分为三大类:创建型模式、结构型模式、行为型模式 , 具体如下图:

文章插图
二、工厂模式工厂模式分为简单工厂模式、工厂方法模式和抽象工厂模式 。其中简单工厂模式并不属于23种设计模式 , 但并不影响它的广泛使用 。在
JDK的源码当中 , 就存在着许多这样的例子 。2.1简单工厂模式我们先来看一段代码:
public static void main(String[] args) {// 日历类Calendar calendar = Calendar.getInstance();SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println("当前时间为:" + simpleDateFormat.format(calendar.getTime()));calendar.add(Calendar.HOUR,2);System.out.println("当前时间加了两个小时后,时间是: " + simpleDateFormat.format(calendar.getTime()));}这段代码 , 大家应该比较熟悉 , 通过对Calendar的一系列操作 , 打印出当前时间和当前时间加两个小时后的时间 , 这里我们来看看结果:
文章插图
结果正和我们想象的一样 , 两次打印出来的时间相隔两个小时 。但我们今天的重点是
Calendar calendar = Calendar.getInstance()这段代码 , 通过getInstance()方法拿到了Calendar 类的实例 。来看看具体的源代码:public static Calendar getInstance(){return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));}//代码不全 , 有兴趣的朋友可以去看JDK源码 private static Calendar createCalendar(TimeZone zone, Locale aLocale){// 中间的代码省略.....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;}}}// 中间的代码省略.....return cal; }可以看出 , getInstance()方法里面调用了createCalendar()方法来得到Calendar类的实例 , 最后返回给调用者 。而createCalendar()方法中通过switch(){case}的判断来返回所对应的Calendar类的实例 , 这其实就是简单工厂模式的一种应用 。看完简单工厂模式在
JDK中的应用之后 , 我们来设计一下自己的例子:小明家新开了一家小工厂 , 接了一单生意 , 帮助海尔(Haier)集团生产冰箱 , 并需要设计相应的方案 。小明本身也是程序员出身 , 思考一会后就写出了下面的代码:
/** * 冰箱 */public interface IFridge {// 生产冰箱public void createFridge();}/** * 海尔 */public class Haier implements IFridge {@Overridepublic void createFridge() {System.out.println("生产海尔冰箱...");}}客户端调用代码:public static void main(String[] args) {IFridge iFridge = new Haier();iFridge.createFridge();}看上面的代码 , 父类IFridge类指向子类Haier类的引用 , 应用层需要依赖于Haier 。如果业务扩展 , 后续增加格力(Gree)甚至更多 , 那么客户端这里的代码会越来越臃肿 。所以 , 我们要想办法将这种依赖减弱 , 将创建IFridge对象的细节隐藏掉 。我们用简单工厂模式优化一下:创建
Gree格力类/** * 格力 */public class Gree implements IFridge {@Overridepublic void createFridge() {System.out.println("生产格力冰箱...");}}创建FridgeFactory工厂类/** * 冰箱工厂 */public class FridgeFactory {// 创建对应的 IFridge 实例public static IFridge createFridge(String name){if ("haier".equals(name)){return new Haier();} else if ("gree".equals(name)){return new Gree();}return null;}}修改客户端调用的代码:public static void main(String[] args) {// 海尔IFridge haier = FridgeFactory.createFridge("haier");haier.createFridge();// 格力IFridge gree = FridgeFactory.createFridge("gree");gree.createFridge();}这样来看 , 虽然代码多了 , 但维护起来以及扩展起来就方便很多 , 来看一看类图:
文章插图
当然 , 上面的
FridgeFactory代码中依旧有些问题 , 如果我们需要增加生产美的(Midea)冰箱 , 那么我们就需要去修改createFridge()方法的代码 , 显然违背了开闭原则 , 我们来改造一下:修改
FridgeFactory工厂类/** * 冰箱工厂 */public class FridgeFactory {// 创建对应的 IFridge 实例public static IFridge createFridge(String className){try {if (null != className && !"".equals(className)){// 反射return (IFridge)Class.forName(className).newInstance();}}catch (Exception e){e.printStackTrace();}return null;}}修改客户端调用的代码public static void main(String[] args) {// com.xxx.Haier换成自己 项目中 Haier 所在的位置海尔IFridge haier = FridgeFactory.createFridge("com.xxx.Haier");haier.createFridge();// com.xxx.Gree换成自己 项目中 Gree 所在的位置格力IFridge gree = FridgeFactory.createFridge("com.xxx.Gree");gree.createFridge();}优化之后 , 我们再也不需要随着业务的提升而去修改FridgeFactory类中的代码了 。但是依旧有一个问题 , createFridge()方法中的参数是字符串 , 如果有人乱填怎么办 , 那不就报错了 , 所以再来优化一下:修改
FridgeFactory工厂类/** * 冰箱工厂 */public class FridgeFactory {// 创建对应的 IFridge 实例public static IFridge createFridge(Class<? extends IFridge> clazz){try {if (clazz != null){return clazz.newInstance();}}catch (Exception e){e.printStackTrace();}return null;}}修改客户端调用的代码public static void main(String[] args) {// 海尔FridgeFactory.createFridge(Haier.class).createFridge();// 格力FridgeFactory.createFridge(Gree.class).createFridge();}再来看一下类图:
文章插图
简单工厂模式虽然好用 , 但也有它的局限性:工厂类的职责过重 , 不利于扩展更为复杂产品结构 。
2.2工厂方法模式定义一个创建对象的接口 , 但让实现这个接口的类来决定实例化哪个类 , 工厂方法让类的实例化推迟到子类中进行 。
在工厂方法模式中用户只需要关心所需产品对应的工厂 , 无须关心创建细节 , 而且加入新的产品符合开闭原则 。
随着小明家新工厂的生意火爆 , 各类的订单都纷涌而至 , 各个牌子的厂家都想让小明家的工厂生产冰箱 , 小明无奈只能开了分工厂 , 并根据客户的品牌名给工厂取了对应的名字 , 其中海尔工厂生产海尔的冰箱 , 格力工厂生产格力的冰箱 , 美的工厂生产美的的冰箱 。用代码演化就是下面这般:
IFridgeFactory类接口public interface IFridgeFactory {public IFridge createIFridge();}海尔// 海尔工厂public class HaierFactory implements IFridgeFactory {@Overridepublic IFridge createIFridge() {return new Haier();}}格力// 格力工厂public class GreeFactory implements IFridgeFactory {@Overridepublic IFridge createIFridge() {return new Gree();}}美的/** * 美的 */public class Midea implements IFridge {@Overridepublic void createFridge() {System.out.println("生产美的冰箱...");}}// 美的public class MideaFactory implements IFridgeFactory {@Overridepublic IFridge createIFridge() {return new Midea();}}客户端调用:public static void main(String[] args) {// 格力new GreeFactory().createIFridge().createFridge();// 海尔new HaierFactory().createIFridge().createFridge();// 美的new MideaFactory().createIFridge().createFridge();}这里其实就是细化了工厂 , 将业务拆分 , 利用了设计模式原则中的单一职责原则 , 让每个品牌对应工厂只干一件事 , 不去掺和其他品牌的事情 。来看一看类图:
文章插图
工厂方法模式适用于一下场景:
- 创建对象需要大量重复的代码
- 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
- 一个类通过其子类来指定创建哪个对象
- 类的个数容易过多 , 增加复杂度
- 增加了系统的抽象性和理解难度
这个定义读起来相当的拗口 , 很抽象 , 不好理解 。还是和上面的例子结合来说明:
在生产完一批冰箱并上市售卖之后 , 美的、格力、海尔等公司非常满意 , 慢慢的将自己家的空调、热水器也交给小明家的工厂去生产了 。小明为此在对应的品牌工厂有开辟了对应的生产设备的空间(这里为了大家看的方便 , 我将所有的代码都放上去):
冰箱、空调、热水器接口
// 冰箱public interface IFridge {// 生产冰箱public void createFridge();}// 空调public interface IAirConditioner {// 生产空调public void createAirConditioner();}// 热水器public interface IWaterHeater {// 生产热水器public void createWaterHeater();}海尔/** * 海尔 冰箱 */public class HaierFridge implements IFridge{@Overridepublic void createFridge() {System.out.println("生产海尔冰箱...");}}// 海尔 空调public class HaierAirConditioner implements IAirConditioner {@Overridepublic void createAirConditioner() {System.out.println("生产海尔空调...");}}// 海尔热水器public class HaierWaterHeater implements IWaterHeater {@Overridepublic void createWaterHeater() {System.out.println("生产海尔热水器...");}}格力/** * 格力 冰箱 */public class GreeFridge implements IFridge {@Overridepublic void createFridge() {System.out.println("生产格力冰箱...");}}// 格力 空调public class GreeAirConditioner implements IAirConditioner {@Overridepublic void createAirConditioner() {System.out.println("生产格力空调...");}}// 格力热水器public class GreeWaterHeater implements IWaterHeater {@Overridepublic void createWaterHeater() {System.out.println("生产格力热水器...");}}美的/** * 美的 冰箱 */public class MideaFridge implements IFridge{@Overridepublic void createFridge() {System.out.println("生产美的冰箱...");}}// 美的 空调public class MideaAirConditioner implements IAirConditioner {@Overridepublic void createAirConditioner() {System.out.println("生产美的空调...");}}// 美的热水器public class MideaWaterHeater implements IWaterHeater {@Overridepublic void createWaterHeater() {System.out.println("生产美的热水器...");}}工厂接口public interface IFactory { // 冰箱public IFridge createIFridge(); // 空调public IAirConditioner createIConditioner(); // 热水器public IWaterHeater createIWaterHeater();}海尔工厂// 海尔工厂public class HaierFactory implements IFactory {// 冰箱@Overridepublic IFridge createIFridge() {return new HaierFridge();}// 空调@Overridepublic IAirConditioner createIConditioner() {return new HaierAirConditioner();}// 热水器@Overridepublic IWaterHeater createIWaterHeater() {return new HaierWaterHeater();}}格力工厂// 格力public class GreeFactory implements IFactory {// 冰箱@Overridepublic IFridge createIFridge() {return new GreeFridge();} // 空调@Overridepublic IAirConditioner createIConditioner() {return new GreeAirConditioner();} // 热水器@Overridepublic IWaterHeater createIWaterHeater() {return new GreeWaterHeater();}}美的工厂// 美的public class MideaFactory implements IFactory {// 冰箱@Overridepublic IFridge createIFridge() {return new MideaFridge();} // 空调@Overridepublic IAirConditioner createIConditioner() {return new MideaAirConditioner();}// 热水器@Overridepublic IWaterHeater createIWaterHeater() {return new MideaWaterHeater();}}客户端调用public static void main(String[] args) { // 海尔工厂HaierFactory haierFactory = new HaierFactory();haierFactory.createIFridge().createFridge();haierFactory.createIConditioner().createAirConditioner();haierFactory.createIWaterHeater().createWaterHeater(); // 格力工厂GreeFactory greeFactory = new GreeFactory();greeFactory.createIFridge().createFridge();greeFactory.createIConditioner().createAirConditioner();greeFactory.createIWaterHeater().createWaterHeater();// 美的工厂MideaFactory mideaFactory = new MideaFactory();mideaFactory.createIFridge().createFridge();mideaFactory.createIConditioner().createAirConditioner();mideaFactory.createIWaterHeater().createWaterHeater();}类图
文章插图
从上面一大堆的代码 , 尤其是类图 , 我们可以很明显的感觉到 , 抽象工厂可以完美清晰的描述海尔、格力、美的三个品牌的冰箱、空调、热水器的庞大体系 。但也正因为如此 , 抽象工厂给我们的视觉冲击有些大 , 能很明显的感觉到系统的复杂性、抽象性以及系统的极难扩展性;并且这里还隐藏着一个违背开闭原则的问题:
在工厂接口
IFactory类中 , 如果在日后的产品升级当中 , 需要增加生产洗衣机的业务 , 那这里修改之后 , 所有实现IFactory接口的类都需要变动 , 很大程度增加了系统的不稳定性 。【java设计模式有几种 5:设计模式的分类及工厂模式详解 Java设计模式】也正因为如此 , 在实际的业务开发中 , 我们不应该有着强烈的强迫症和洁癖 , 认为一个系统的结构设计必须要完美的符合各种原则 。要结合实际的业务去思考 , 如果系统结构的等级更新不频繁的话 , 不遵守某些原则也是有必要性的 , 毕竟所有的技术都是为业务而服务的 。
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
