高阶函数和模版方法模式
这是「从函数式角度看设计模式」的第三篇。目的是从和OOP不同的角度重新审视设计模式。
实际上感觉都没什么好写的?
这是「模版方法模式」的定义和实现方法:
模板方法模式是一种行为设计模式, 它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。
模板方法模式建议将算法分解为一系列步骤, 然后将这些步骤改写为方法, 最后在 “模板方法” 中依次调用这些方法。 步骤可以是抽象的, 也可以有一些默认的实现。 为了能够使用算法, 客户端需要自行提供子类并实现所有的抽象步骤。 如有必要还需重写一些步骤 (但这一步中不包括模板方法自身)。
一个典型的例子是RPG游戏里,有不同的角色和职业,但是都会做出攻击防御之类的同样类型的动作,或者是一个数据处理软件,需要对不同格式,例如TXT、MD、HTML进行类似的文字处理动作。
但是仔细想,这不就是高阶函数嘛。比如说文字处理的这个例子,基类就可以设计为留下一个「坑」,接受一个lambda,来描述具体的处理流程,而不需要关心具体哪个格式处理哪种文件。
1 |
|
这里的lambda是一个Supplier
(从Java的角度),但是实际上根据需求也可以有任意的入参,并且有或没有返回值。
拿到了这个lambda后,在主函数内就可以对他进行各种变换了。
1 |
|
这也是典型的「依赖注入」,虽然没有用到一行注解,但是具体的算法流程被外置了。
相比之下,模版方法模式大概是这样的写法。
1 |
|
比起OOP设计模式,有什么好处呢?
最大的好处大概是不再需要声明类型的继承关系。这样一来,一方面少写了很多代码,另外一方面lambda注入的关系是松耦合的,而继承是强耦合的。Lambda的形式显然可维护性也会好许多。
实际上,模版方法模式倒不如说是在用OOP的继承关系的「多态」来模拟这种「算法不依赖于基类」的关系。不过呢,函数式的做法,本就可以更好地表达「多态」关系,至于控制反转,更是回调天然可以表达出来的。