设计模式在游戏中的运用(工厂模式)

时间:2021-12-14 20:49:13

工厂模式分为简单工厂,工厂方法,抽象工厂三种模式。

我们先来说说为什么要使用工厂模式,因为我主要是做游戏的,我们这边就拿游戏来举例子,假设有一个rpg游戏,需要在地图中加载怪物,因为这种需求可能从多个地方触发,比如碰到一个陷阱加载几个怪物,然后可能根据特定时间又要加载怪物,还可能使用一个道具加载几个怪物。

如果我们把创建怪物的过程分别写在陷阱的处理,时间处理,道具处理过程中,则创建怪物的逻辑就分散开来了,如果此时我们想增加一个新功能,即维持地图中一个怪物的上限,这样我们必须在每个创建怪物的地方都维持一个怪物的记录,这样是非常不好的。如果要添加更多的功能,就更加麻烦。

所以需要统一怪物的创建过程,我们创建一个工厂类来统一怪物的创建,以及怪物池的维护,比如设定当前地图的怪物上限,超出之后就不能再创建。任何一个需要创建怪物的地方都可以调用工厂类的方法,同时工厂类还可以写一些帮助方法更方便的完成怪物的创建,比如通过等级区间随机返回怪物,通过属性返回怪物之类的。

以上就是工厂模式的优势,那么接下来我们区分一下简单工厂,工厂方法,抽象工厂三种模式,同样以上面的游戏作为背景。

假设简单工厂当前有一个方法,创建史莱姆

这个时候我们需要给游戏添加难度功能,难度越高,怪物越强。

所以我们这个时候要创建新的怪物类,例如,高难度史莱姆,当然如果高难度史莱姆只是比史莱姆属性更高,那么可以直接对属性进行运算,不过一般来说高难度怪物的行为逻辑也不同,所以需要创建一个新的类。

那么这个时候我们就需要给简单工厂新的方法,创建高难度史莱姆,是不是感觉很变扭?当然除了直接添加方法,还可以将难度作为一个参数传入简单工厂,然后简单工厂根据难度判断返回哪个对象。但无论怎么样,都会破坏简单工厂的封装性。

如果我们需要增加更多的难度,则简单工厂里的case判断就会越来越多,所以这个时候需要工厂方法模式来帮助了。

工厂方法模式对以上问题的解决方法就是提供一个普通史莱姆怪物工厂,困难史莱姆怪物工厂,然后两个工厂内部分别有对史莱姆的创建方法,具体使用哪一个工厂根据实际难度来确定,这个时候如果增加更多的难度,例如疯狂难度,只需要添加新的疯狂史莱姆怪物工厂继承于抽象的怪物工厂,而不用修改工厂本身。

抽象工厂其实和工厂方法非常接近,工厂方法模式每个工厂只负责一个对象的创建,例如史莱姆工厂只负责创建史莱姆,抽象工厂模式每个工厂负责一系列有关联的对象的创建,所以如果我们实现一个普通怪物工厂,分别实现对普通史莱姆,普通巨龙的创建,那他就是抽象工厂。

总结一下 假设有两种怪物,史莱姆和巨龙,两种难度,普通和困难
简单工厂模式下
一个工厂有四个方法创建普通史莱姆 创建普通巨龙,创建困难史莱姆,创建困难巨龙
工厂方法模式下
四个工厂 普通史莱姆工厂,困难史莱姆工厂,普通巨龙工厂,困难巨龙工厂,每个工厂只有一个方法就是创建对应的怪物
抽象工厂模式下
两个工厂 普通怪物工厂 负责创建普通史莱姆,普通巨龙,困难怪物工厂,负责创建困难史莱姆,困难巨龙。

好像看起来抽象工厂最好,那么是不是抽象工厂一定比简单工厂和工厂方法更好呢?

其实我们使用设计模式是解决实际问题的,只有出现新的问题,才会去思考新的解决办法,就像上面所说的,因为我们需要在多个地方创建敌人,才会引入简单工厂,如果我们的游戏非常简单,只会在一种情况下创建敌人,比如加载地图时,那么创建敌人的逻辑完全可以写在加载地图的后面。同理,如果我们的游戏只有一种难度,那么也没有什么引入抽象工厂的必要。而如果我们的游戏没有难度变化,但是需要对每种怪物的创建都进行记录,例如,整个游戏中一共只会出现100只史莱姆,100只巨龙,杀完就没了。这个时候工厂方法模式说不定更好,因为他是对每一种怪物都有一个对应的工厂。