工厂,又称制造厂,是一类用以生产货物的大型工业建筑物。大部分工厂都拥有以大型机器或设备构成的生产线。在世界近代史中泛指资本主义机器大生产,即使用机械化劳动代替手工劳动的资本主义工业场所。在我们设计模式中也生活着这么一家人,他们分别是简单工厂模式,工厂方法模式和抽象工厂模式,他们都是属于创建型设计模式,这三种创建型模式都不需要知道具体类。我们掌握一种思想,就是在创建一个对象时,需要把容易发生变化的地方给封装起来,来控制变化(哪里变化,封装哪里),以适应客户的变动,项目的扩展。这三种模式按照可维护可扩展的特点来看,工厂方法模式是简单工厂模式的进化,而抽象工厂模式,又是工厂方法模式的进化。
举个简单的例子,春天是播种的季节,我想此刻在我的家-美丽的遥远的安徽,爷爷奶奶正在菜园子里忙着种植蔬菜苗,如果,奶奶只想让菜园单纯的只要种上蔬菜就可以了,那么就用简单工厂,奶奶养育了四个儿女,大过年的一大家子人回来,奶奶总想让那方团圆桌摆上各式各样的菜肴,这个时候就需要用工厂方法才可以实现,就是把共有的东西抽象出来,菜的种类多了,需要的土地规模就会扩大,如果要扩大菜园子的规模,比如一个在村头,一个在村尾,这样工厂方法就无法实现了,就应当用抽象工厂,各种各样的蔬菜,又组成一个菜园子。接下来,依次来讲解一下,三个工厂,依然以我们上述例子:
首先简单工厂模式, 我们把简单工厂模式比喻成菜园子,菜园子有他自己的属性方法,他封转了浇水,施肥,锄草三个方法,要求类是客户端,她只需要调用农活类和菜园子类就可以完成任务,而不需要 一次调用浇水,施肥,锄草所以,实现了封装。一起来看一下她的类图:
如果菜园子中蔬菜的种类越来越多,比如过长豆角,黄瓜,葫芦等这些蔬菜属于攀藤类蔬菜,需要支撑架来支撑她们来进行持续生长,茄子,茼蒿这些蔬菜需要定时削剪叉枝,以保持主干支的养分,这个时候,我们就需要修改代码,首先,我们需要增加支撑架,削剪的类,然后,在菜园子类中改变select或者是if条件分支语句,这样,不仅增加了类,还需要修改原有的类,这样一来,违背了开放-封闭原则,这也就是为什么简单工厂模式不能列入GOF的23中模式的原因之一。
而此时,我们需要把简单工厂模式中的“菜园子”类加以改进,让她符合开放-封闭原则,也就是取出她的select case选择分支语句,让在增加方法的时候只需要添加类,这样便符合开闭原则,而简单工厂和工程方法的区别,也就在此,看看我们的类图是如何实现的。
我们一直都在写一个菜园子的农作物,但是,如果需要写村头和村尾两个菜园子的农作物,而且我们可以随时切换知道两个菜园子的农作物情况,那么,我们就应该考虑扩充工厂方法模式,而需求不断演化的过程中,我们就重构了一个非常重要的设计模式:抽象工厂模式,类图如下:
无论是简单工厂模式、工厂模式还是抽象工厂模式,它们本质上都是将不变的部分提取出来,将可变的部分留作接口,以达到最大程度上的复用。拿一个生产水杯(cup)的工厂举例:起初,不用工厂模式,我必须在生产水杯之前知道水杯的材料和形状等水杯的所有特征才能生产,这就是我们的new Cup();这个Cup必须是具体的。
厂主发现同一形状的被子,只是材料不同,如一个是玻璃(glass)的,一个是瓷(china)的,但是确要两条生产线,显然有资源浪费的嫌疑。现在厂主生产杯子时先不让生产线知道我要产的是玻璃的还是瓷的,而是让它在不知道具体材料的情况下先做它能做的,等到它把模具做好,只需要向其中填充玻璃原料或者瓷原料就可以造出同一形状的具体杯子了。所以就有了简单工厂模式。原来是Cup cup=new Cup;现在是SimpleCupFactory.createCup(String cupName),根据cup的名字生产Cup,而createCup返回的是一个实现了 Cup接口或抽象类的具体Cup。
简单抽象工厂模式有一个问题,就是当我现在想生产一个同样形状的铁杯时,工厂里并没有定义相应的处理流程,只能更改createCup方法,这就不合理了。我现在只是想生产铁杯,你只要在最后的时候把玻璃原料换成铁的不就行了吗,干嘛还要更改整条生产线呢?于是就有了工厂模式。原来生产线在生产模具的时候还要考虑是为玻璃杯生产的模具还是为铁杯生产的模具,现在它不用管了。CupFactory.createCup()创建Cup.CupFactory是接口或抽象类。实现它的具体子类会创建符合Cup接口的具体Cup。那么现在厂主想要生产水壶(kettle),用工厂模式就不得不再造一条水壶生产线,能不能在水杯生产线同时生产水壶呢?这就是抽象工厂模式。在原CupFactory中加一个createKettle()方法,用来生产水壶。设计之旅,未完待续......