- 前言:
- 在平时编程中,构建对象最常用的方式是 new 一个对象。乍一看这种做法没什么不好,而实际上这也属于一种硬编码。每 new 一个对象,相当于调用者多知道了一个类,增加了类与类之间的联系,不利于程序的松耦合。其实构建过程可以被封装起来,工厂模式便是用于封装对象的设计模式。
- 工厂模式将对象的构造过程封装,与业务代码进行分离,降低了代码耦合度。
- 简单工厂:
- 不算是设计模式,只是一种编码习惯
- 例如水果类,子类为各种水果,构建具体水果对象时,通过额外的工厂类将构建的步骤抽出来,根据type来创建水果实例并返回的过程。
- 调用者无需知道具体水果的生产细节,当生产过程需要修改时也无需更改调用端。
- 工厂模式:
- 将对象的实例化推迟到了子类。定义了一个创建对象的接口,由子类决定要实例化的是哪一个子类。
- 采用的还是继承方面的思想。
- 以 Head First书中的工厂模式为例,开了一个披萨连锁店。将披萨制作过程交由各个连锁店,打包、切片等方式还是按照总店模板的方式进行。
- 由此可以引申出一种使用方式:
- 披萨总店是抽象类父类,且该类中的披萨创建方法是一个抽象方法需要由子类实现,在父类下单时调用了该创建方法。
- 连锁店是披萨总店抽象类的子类,并且实现了父类的披萨的创建的抽象方法。
- 各个连锁店才是披萨的实现类,因此调用方其实也是这些子类即披萨连锁店。
- 抽象工厂模式:
- 当Factory 中只有一个抽象方法时,或许还看不出抽象工厂模式的威力,实际上抽象工厂模式主要用于替换一系列方法。
- 例如将程序中的 SQL Server 数据库整个替换为 Access 数据库,使用抽象方法模式的话,只需在 IFactory 接口中定义好增删改查四个方法,让 SQLFactory 和 AccessFactory 实现此接口,调用时直接使用 IFactory 中的抽象方法即可,调用者无需知道使用的什么数据库,我们就可以非常方便的整个替换程序的数据库,并且让客户端毫不知情。
- 抽象工厂模式很好的发挥了开闭原则、依赖倒置原则,但缺点是抽象工厂模式太重了,如果 IFactory 接口需要新增功能,则会影响到所有的具体工厂类。使用抽象工厂模式,替换具体工厂时只需更改一行代码,但要新增抽象方法则需要修改所有的具体工厂类。所以抽象工厂模式适用于增加同类工厂这样的横向扩展需求,不适合新增功能这样的纵向扩展。
- 以披萨为例:
- 将创建披萨的抽象方法改为一个单独的接口类,具体的实现在创建披萨时选择不同的工厂去实现。
- 新的工厂接口类中不仅有 create( )方法,还有各种自定义的方法,所有实现类需要实现这个接口类的方法。
- 抽象工厂模式面对扩容、新增是开放的,但是当接口类需要一个新的方法时,所有的实现类也需要去实现这个新的方法,改动量可能是巨大的。因此建议使用抽象工厂模式时,将抽象力度定义的越小越好,所有的抽象都是原子性的那么在以后的改动就会比较少。
- 工厂模式与抽象工厂模式的区别:
- 工厂模式是采用继承的方式使用子类去抽象创建的过程,也就是整个创建是一个抽象(抽象方法)
- 抽象工厂模式是采用接口类的方式去抽象,当只有一个创建方法时与工厂模式几乎没有区别,都是只抽象了一个整体的创建过程;但是如果创建过程变得动态了,包括材料、酱料的改变,那么此时的抽象工厂可以使用自定义的材料接口方法,使整个创建过程中的每个步骤都成了抽象,也就是二者相比抽象工厂的抽象力度更小。
- 实际编码中,也可以将工厂模式与抽象工厂模式相结合,制作披萨是抽象的,制作过程可以抽象成一个个的细节成一个大的接口类。
- 逻辑图:
# 码字不易,大佬们觉得文章有帮助,动动小手点个赞支持一下,蟹蟹!