北川广海の梦

北川广海の梦

设计模式:享元模式与命令模式

2021-11-08

享元模式

假设这样一个场景,在一款太空飞行射击游戏中,我们实现了大量子弹倾泻的场景,满屏的弹幕,同时存在数万个子弹。但是这样一款游戏在一台内存较低的电脑上却无法运行。这是由于每一个子弹都是一个游戏对象,如此数量的子弹占用了大量的内存空间。
而进入每一个对象内部,我们发现,这些子弹只有坐标、方向不一样。而它们所使用的贴图、颜色,甚至速度都是完全相同的。但是我们在每一个子弹对象中,都大量冗余了这些数据。导致占用了大量内存。

我们可以将这些对象间存在的大量相同的东西提取出来,组成一个享元对象。而每一个对象只保留自己不同的属性,并且持有对一个享元对象的引用即可。而当面临不同的情境的时候,享元对象也可以有多个。此时,我们可以通过工厂模式,实现一个子弹工厂以及一个享元工厂。优雅的解决不同场景的问题。

仅在程序必须支持大量对象且没有足够的内存容量时使用享元模式。
享元模式会使代码变得更加复杂。

如果整个系统中的所有共享状态可以被统一成一个享元对象,此时就会很像单例模式,但是单例模式类只会有一个实例。而享元对象类虽然唯一,但是可以存在多个实例,实例的内部属性可能不同。而单例的内部属性是可变的,享元对象的内部属性不应该改变。

命令模式

在GUI应用中,我们通常需要针对每一个按钮做出响应。而如果将响应逻辑(业务逻辑)大量写在GUI层,代码将变得非常难以维护。因为业务逻辑也GUI代码产生了大量混杂。一个正确的做法是将所有执行的操作抽象成为命令对象,然后通过命令对象完成业务逻辑的实现,达到解除耦合的目的。

具体的实现命令的对象,被命令对象所引用。例如一个发送邮件的命令,那么命令对象中需要持有一个邮件客户端对象。这个具体对象被称为接收者(Receiver),并且客户端能够动态的设置在不同的场景执行不同的命令。

通过命令模式,我们还能实现一个命令队列,一组一组的执行操作。并且每个命令可以实现一个Undo方法,达到撤销的目的。

命令模式和策略模式有相似之处,但是策略模式注重的是完成某一件事情的不同方式,命令模式则是不同的命令对应不同的方式。在使用策略模式时,客户端选择的是方法,而命令模式下,客户端则是选择执行什么操作。

状态模式是通过状态对象,在不同状态下执行不同操作。命令模式可以与状态模式形成补充,客户端无需根据某一状态判断应该执行什么命令,而是委托命令对象来判断。命令对象持有在执行此命令下时所拥有的状态引用。调用对应状态对象实现命令即可。