设计模式笔记(五)– 策略模式

策略模式可以根据不同的行为使用不同的策略。


问题提出

假设我们要存储用户上传的图像。

类ImageStorage有一个store方法,在store方法里,我们先对图像进行压缩,再给图像应用某种滤镜,然后进行存储。

这个实现有一些问题。

首先,它违反了单一职责原则,store方法不仅负责存储图像,还负责了压缩图像,以及给图像应用滤镜。

其次,添加新的压缩算法或新的滤镜需要修改原来的实现,修改比较困难。

面向对象的四个原则:封装、抽象、继承、多态性,我们该选择哪个来解决这个问题呢?


解决方案

ImageStorage类里可能变化的是压缩算法和应用的滤镜。应用多态性原则我们将它们抽象成接口。

首先是压缩算法。

我们将它抽象成Compressor接口,ImageStorage只依赖于该接口。JpegCompressor、PngCompressor或其他更多的压缩算法实现Compressor接口,这样就达到了开放闭合原则。我们可以通过添加新的Compressor实现类来扩展算法,但同时不修改已有代码。

然后是滤镜。

将其抽象成Filter接口,BlackAndWhite和HighContrast实现该接口。ImageStorage只依赖Filter接口。

这就是策略模式(startegy pattern)。

我们发现,策略模式与状态模式(见下图)很像。

它们之间的区别是:

状态模式是对状态的多态化。

而策略模式并不是针对某种状态,它根据不同的行为使用不同的策略。


代码实现

创建接口Compressor,定义compress方法,实际场景中compress方法的定义类似这样:

byte[] compress(byte[] image);

这里为了简单,定义成:

void compress(String fileName);

再创建JpegCompressor、PngCompressor,实现Compressor接口。

类似地,我们也定义Filter接口,以及类BlackAndWhiteFilter和类HighContrastFilter。

回到ImageStorage类,属性compressor和filter类型分别变更为接口Compressor和接口Filter,store方法中调用compressor.compress和filter.apply即可。

到Main类进行测试。我们可以灵活选择压缩算法和应用滤镜对图像进行处理。

明天我们添加某种压缩算法,或添加某种滤镜,只需添加相应的实现类即可,而无需对现有的代码进行修改。

目前我们更改图像的压缩算法或更改应用的滤镜,都需要重新生成一个ImageStorage实例,稍有点笨重。可以将压缩算法和滤镜的选择移到store方法里作为参数,这样只需一个ImageStorage实例即可实现多文件不同格式的压缩滤镜处理,更加灵活。


小结

策略模式与状态模式有点类似,不过它不是状态的多态性,而是可以根据不同的行为使用不同的策略。

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注