轻松理解设计模式:3.抽象工厂模式(创建型)

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

前言

设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。也就是说,它是解决特定问题的一系列套路,是前辈们的代码设计经验的总结,具有一定的普遍性,可以反复使用。其目的是为了提高代码的可重用性、代码的可读性和代码的可靠性。

经过汇总的23种设计模式它是总结了面向对象设计当中最有价值的经验。对之前来讲可能是对其中部分设计模式还是相对来说熟悉的但仔细琢磨还是会有些疑问,正好在目前相对来说有更多的业余时间,可以来一次重新学习设计模式!

本篇内容关于抽象工厂模式。包含抽象工厂模式的概念以及差异

定义

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类 —— 《Head First 设计模式》

按照这个定义的描述,好像是和工厂方法模式没有啥不同的。同样是提供一个抽象类或者接口,里面提供一个方法用于创建对象且不需要指明具体类。——关于工厂方法模式看这篇《轻松理解设计模式(创建型)2、工厂方法模式》

这里画一个抽象工厂大概的UML图:

就图的区别而言,工厂方法模式只提供一个创建实例的方法。而对于图上的结构一个具体工厂需要实现接口规定的多个创建实例方法。

客户代码最终获取的一系列产品的具体实例,取决于注入的具体工厂

 public class Person {
     FoodFactory factory = new 徐老师早餐店();
     public void eat() {
         // 获取食物
         Food 老徐炒面 = factory.ceate面条("炒面");
         Food 老徐粉包 = factory.ceate包子("粉包");
         // 吃
         System.out.println("我开吃啦"+老徐炒面+老徐粉包);
     }
 }
复制代码

疑问

按照上面所说确实抽象工厂多了方法,但工厂方法模式一样可以实现这样的功能,到底有什么区别呢?

工厂方法模式只提供一个抽象的工厂方法,如果要和抽象工厂创建对象的范围一样的话,那么这个唯一的工厂方法的返回类型就要相对来说大一层。且由各个子类来提供具体创建的是这个大类型下的哪个具体类最终都由大类来接收。对于抽象方法来说是直接指定了需要创建的各个类型。这样这个类型既不是具体也不至于太抽象,便于使用,一套产品各自有各自的使用点。

工厂方法是由子类自行决定实例化哪个类,而抽象工厂是自己决定实例化哪个类。

在Java当中有哪些地方使用过这些工厂模式呢?

简单工厂

 public interface BeanFactory {
     Object getBean(String beanName);
 }
复制代码

Spring的BeanFactory就是简单工厂模式,通过getBean方法传入bean名称获取对应实例。具体实例是由一开始扫描配置时创建的并加载到map当中的,当getBean时取出返回。采用简单工厂的Map实现方式。

工厂方法

同样在Spring当中也有工厂方法模式的体现AbstractFactoryBean 对象的其他前后的完善操作都由其他方法完成,而具体的创建由其各个子类实现createInstance抽象方法。这些子类它们不需要管对象后续或者前置操作仅仅完成创建。而其他操作均可保证按照固定的流程,只是创建的对象具有多样性。

抽象工厂

比如在Java.sql包下有一个接口叫做Connection(工厂接口)也就是数据库连接对象应该都不陌生。需要各个数库厂商提供实现像MySQL、Oracle等

如下图所示:

这个接口它明确的指定了要创建的各个产品的方法,MySQL或者Oracle都对其有一套的实现来创建这一套产品家族的具体类的实例。且它们也对产品类也有一套具体的实现。当换成工厂实例是MySQL提供,那么创建的Statement(抽象的产品)就是MySQL的对于这个产品接口的具体产品类。而代码中永远使用的是抽象的,工厂只出现Connection这样的接口而没有具体的实现类,而代码中获取的产品Blob、Clob、Statement也是由这些接口接收。

当使用这套产品家族的另一套具体产品实现时,只需要配置新工厂的方法实现生产现在要使用的一套产品即可。整个代码流程都是抽象的固定的。不需要具体的更改而改代码。

总结

回顾整个工厂模式是用来封装对对象的创建,从而减少程序与具体类的耦合。它符合我们的依赖倒置原则——避免依赖具体类型,尽量依赖抽象。而工厂方法与抽象工厂各有不同,前者将类的实例化延迟到子类进行,有新的产品类就增加新的具体工厂。后者抽象工厂模式更侧重于在接口规范一组产品类型,每个具体工厂类是对其全部一套产品的创建进行实现,若有新的一套产品实现则可以扩展一个具体工厂,如果产品家族有新增产品则各个工厂都需要新增实现新产品的创建方法。可以说这些工厂模式是面向抽象编程的一个最佳实践。