项目组在和外部系统对接,花了好长一段时间对以前的打印逻辑做修改,修改了8次的bug,才实现了当前的外接系统的打印功能,上线的前一刻又发现此次的改动对以前的逻辑产生关联影响,哎,不谈了,原因很简单,随着外接系统的增多,实现的打印方式和功能已经很多了,而此时几千行的代码看看已经让人崩溃了,改动的难度就更大了。
不得不重构了,梳理业务和代码逻辑后,决定采用工厂+策略的模式进行重构。
工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来。
简单工厂实现客户买宝马的例子:
- class Factory {
- static function createBMW(type){
- switch (type) {
- case 320:
- return new BWM320();
- case 523:
- return new BMW523();
- }
- }
- /**
- * 创建工厂的接口
- *
- */
- interface FactoryBMW {
- function createBMW();
- }
- /**
- *
- * 创建BWM320车
- */
- class FactoryBWM320 implements FactoryBMW {
- function createBMW($type){
- return new BWM320();
- }
- }
- /**
- *
- * 创建BWM523车
- */
- class FactoryBWM523 implements FactoryBMW {
- function createBMW($type){
- return new BMW523();
- }
- }
1)系统中有多个产品族,而系统一次只可能消费其中一族产品。
2)同属于同一个产品族的产品以其使用。
抽象工厂模式的各个角色(和工厂方法一样):
1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。
4)具体产品角色:具体工厂角色所创建的对象就是此角色的实例。
策略模式:定义了不同的算法族,并且之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
Context(应用场景):
l 需要使用ConcreteStrategy提供的算法。
l 内部维护一个Strategy的实例。
l 负责动态设置运行时Strategy具体的实现算法。
l 负责跟Strategy之间的交互和数据传递。
Strategy(抽象策略类):
l 定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,Context使用这个接口调用不同的算法,一般使用接口或抽象类实现。
ConcreteStrategy(具体策略类):
l 实现了Strategy定义的接口,提供具体的算法实现。
有了上面的知识,重构就理顺了。外部关联系统部需要知道我怎么实现打印的,只需要告诉我打印需要的内容和打印机就好了。
关联系统A需要打印a,b,c三种类型的材料,并且采用彩色打印和黑白打印两种方式混合的方式。
在我们系统中,目前支持单页彩打,单页黑白打印,多页彩打,多页双面彩打,多页双面黑白打,以及以上的方式是否需要盖章,是否需要防伪水印,是否需要电子签名等多种方式的打印。讲以上的打印功能分成打印策略及子类,盖章策略及子类,防伪策略及子类三个策略类。
采用抽象工厂的方式,根据A系统的要求,在抽象工厂中生成适合的工厂类,调用合适的策略类就搞定了,再增加关联系统的时候,只需要再增加策略方法就搞定了。
重构前,原来的多个外部关联系统的N种打印逻辑代码有近4000行,重构后用1000多行代码完成整个流程,简单明了,呵呵。