在单例模式的学习之后,今天是工厂方法模式,事不宜迟,马上开始吧。
工厂方法模式
首先,还是先来介绍一下,什么是工厂方法模式呢?
定义一个用于创建对象的接口,让子类决定实例化哪一个类。
工厂方法是一个类的实例化延迟到其子类。
那么具体是什么样的呢?
我们先来看一段工厂方法模式的模板代码:
所有代码都在github仓库中,可以clone下来看的~
那么来梳理一下工厂方法模式的结构:
首先创建一个虚拟工厂类作为所有工厂类的规范(尽管现在只有一个工厂,后续会有一个虚拟工厂类对应多个具体工厂类的情况,此处按下不表),虚拟工厂类中定义了create方法,毕竟所有的工厂类都需要能够创建相应的实例对象。
创建需要的对应的具体工厂类,在具体工厂类中定义如何创建一个具体的实例对象,需要注意的是,对应的返回值定义的是一个虚拟产品类,因为工厂方法模式就是对于一个范围中的不同的产品能够屏蔽产品类的具体实现方式,比如后续的会提到的例子(你可能对于饮品来说,有可乐,橙汁,白开水,那么他们都同属于虚拟产品类Drink,具体的咱们后面到场景类中再聊)。
可能这么说还是比较抽象,引入今天的一个例子:小男孩买饮料
场景是这样的:有一个小男孩在运动之后口渴了,他来到一台自动售货机(就是投币之后按一下就能出一瓶饮料的那种)前,哐哐哐买了三瓶饮料(可乐,橙汁,矿泉水)。对于每瓶饮料来说,他们都可以喝(这是饮料的共性,在程序中也就是一会儿会看到的drink方法),但是每瓶饮料的味道不一样(这是每瓶饮料的特点),因此相应的喝完之后的感受也不太一样(也就是一会儿会看到的feel方法)。
那么就会有如下的场景类:
在运行main方法之后:
可以看到,因为没有对虚拟类的drink方法进行覆写,因此他们的逻辑是一样的。都是 名字 + “已经被喝掉了”。这是每个饮料的共性,毕竟每种饮料至少都是“能够喝的”。
但是看到调用feel方法之后就完全不同了,各位喝不同饮料的时候肯定深有体会。
那么对于这个场景类来说,我们映射到今天的主要内容:工厂方法模式。
虚拟工厂类:自动售卖机的虚拟类,也可以理解为这个世界对于自动售卖机的一种定义,所有的自动售卖机都必须遵循虚拟工厂类中所制定的标准,在虚拟工厂中定义的方法都是所有自动售卖机所具备的。
具体工厂类:就像具体的某一款,XX牌自动售卖机,那么他按照“国际规定”(虚拟工厂类)设计了一款具体的自动售卖机,是有具体的功能的,可以卖饮料的。
虚拟产品类:规定了自动售卖机中所贩卖的内容,比如说之前提到的Drink,说明是“饮品”。同样和虚拟工厂类类似,或者说对于“虚拟类”而言,都是一种设计规范,以及一些通用的方法的声明。
具体产品类:这就更好理解了,咖啡,可乐,橙汁等,都可以是“饮品”这个虚拟产品类的具体产品类,我们还可以举一反三,比如说,巧克力之于甜品,宝马之于汽车,以此类推。
那么将上述的四种类型在我们的场景中串一串:小男孩(Boy场景类,这不重要)来到了一台自动售货机(AbstractVending)前,这是一台XX牌自动售货机(Vending),卖的是饮料(Drink),他很渴,买了三瓶饮料(Drink),分别是可乐(Cola)、橙汁(Orange)、矿泉水(Water),他陆续用相同的方式(比如说都是拧开瓶盖)喝(drink方法)了对应的饮品,产生了不同的感觉(feel方法的覆写)。
那读到这里想必大家应该基本上知道了工厂方法模式是怎么一回事,那我们为什么需要用到它呢?
良好的封装性,代码结构清晰
扩展性非常优秀
屏蔽产品类
上述三点简单来说就是:产品的生产对于用户是透明的。
用户要做的就是两件事:
知道自己需要什么产品
通过工厂类生产产品
设想一下,你现在只知道你想喝一瓶可乐,你站在了自动售货机前,你需要知道怎么去填装一瓶可乐吗,显然是不需要的。因为你是知道饮品的drink方法的,也就是说,你只需要一瓶饮料怎么喝,也就足够了。那么这就给扩展性带来了便利,程序员需要扩展产品时,只要继承的都是同样的虚拟类,那么具体的实现对于用户都是透明的,用户也知道这个虚拟类下的子类都可以用对应的方法,比如说我现在引入了新的饮品(比如说是咖啡),那么它也是可以drink的,同样能够调用feel方法,得到来自咖啡的独特的feeling。
那么到了这个地方,工厂方法模式的基本用法也就讲解完毕了,接下来简单了解一下工厂方法模式的几种扩展吧。
简单工厂模式
多个工厂类
替代单例模式
延迟加载
简单工厂模式
简单工厂模式去掉了上述的虚拟工厂类环节,转而在具体工厂类中使用静态方法直接进行对应的对象的生成。
从使用难度来说肯定对于普通的工厂方法模式是下降的,但是同时也牺牲了对应的工厂方法模式的扩展性,毕竟设想一下,简单工厂模式是去掉了对应的虚拟工厂类,那么每一个工厂都没有一个适用的标准,也就违反了我们最开始所说的依赖倒置原则,无法直接地了解到“这是一个什么工厂”。这是比较关键的。
多个工厂类
就刚才的例子来说,我们是在一个自动售货机中,同时能够得到所有的需要的饮料,换句话说,就是将所有的产品都放在了一个工厂中来进行生产,那么假设说有更多的产品,一百,两百,一千,甚至更多,那么这个工厂类的代码量就会暴增,这时候就需要将工厂分门别类,就像我们上一个简单工厂模式所说的,我们的虚拟工厂类就是这种时候要发挥作用。
我们接下来以专门的自动售卖机为例(一个售卖机只售卖一种饮品):
整体的逻辑和最开始的小男孩买饮料是一致的。
不过小女孩(Girl场景类)就必须跑遍三个自动售货机,才能买到三种饮品。因为都是专门的售货机,每种售货机只会售卖一种饮料。
替代单例模式
这个拓展使用方式和正常的单例模式并没有太多不同,只是创建产品的时候返回单例对象而已,这里就直接看看代码就好了:
延迟加载
这里要稍微提一下,其实这里就是一个缓存的机制,先判断缓存中是否存在需要的对象(或者产品),如果存在就直接返回,不存在才进行对应的创建。(对于缓存有兴趣也可以自行进行搜索,redis的缓存基本上也就是这种思路)。
所有本期的代码都在Github仓库同步更新噢~
https://github.com/Bngel/NoteOfDesignPattern
那么今天的设计模式学习就到这里结束了,下期见~
「艾尔登法环」梅琳娜手办开订 立体手办▪
万代「艾尔登法环」白狼战鬼手办开订 立体手办▪
「夏目友人帐」猫咪老师粘土人开订 立体手办▪
「五等分的新娘∬」中野三玖·白无垢版手办开订 立体手办▪
「海贼王」乌索普Q版手办开订 立体手办▪
良笑社「初音未来」新手办开订 立体手办▪
「黑岩射手DAWN FALL」死亡主宰手办开订 立体手办▪
「盾之勇者成名录」菲洛手办登场 立体手办▪
「魔法少女小圆」美树沙耶香手办开订 立体手办▪
「咒术回战」七海建人粘土人登场 立体手办▪
「五等分的新娘」中野二乃白无垢手办开订 立体手办▪
「为美好的世界献上祝福!」芸芸粘土人开订 立体手办▪
「公主连结 与你重逢」六星可可萝手办开订 立体手办▪
「女神异闻录5」Joker雨宫莲手办开订 立体手办▪
「间谍过家家」约尔・福杰粘土人登场 立体手办▪
「街角魔族 2丁目」吉田优子手办开订 立体手办▪
「火影忍者 疾风传」旗木卡卡西·暗部版粘土人登场 立体手办▪
「佐佐木与宫野」宫野由美粘土人开订 立体手办▪
「盾之勇者成名录」第2季拉芙塔莉雅手办开订 立体手办▪
「咒术回战」两面宿傩Q版坐姿手办开订 立体手办▪
「DATE·A·BULLET」时崎狂三手办开订 立体手办▪
「狂赌之渊××」早乙女芽亚里粘土人开订 立体手办▪
「魔道祖师」魏无羨粘土人开订 立体手办▪
「新·奥特曼」奥特曼手办现已开订 立体手办▪