Java重构面向过程代码_重构之美之一改造面向过程式设计

使用面向对象语言进行过程式设计的例子,可谓俯拾皆是。看这段代码:

publicclassSyncExecutor {publicvoidexecuteSync() {

syncSchools();

syncGrades();

syncFaculties();

}

}

这段代码很清晰,分别执行了对学校、年级与教师信息的同步。一目了然,似乎没有什么问题。然而,如果深入阅读各个同步子方法,就会发现某种坏味道,那就是重复代码。

privatevoidsyncSchools() {

ListsourceSchools=getSourceSchools();

ListtargetSchools=newArrayList();

ListsourceSchoolCodes=getSchoolCodes(sourceSchools);

MaptargetSchoolWithCodeMapping=schoolService.getSchoolWithCodeMapping(sourceSchoolCodes);for(School sourceSchool:sourceSchools) {

String schoolCode=sourceSchool.getSchoolCode();

School targetSchool=targetSchoolWithCodeMapping.get(schoolcode);if(targetSchool==null) {

targetSchool=newSchool(

sourceSchool.getSchoolCode(),

sourceSchool.getSchoolName(),

sourceSchool.getProvinceCode(),

sourceSchool.getSchoolAddress(),

sourceSchool.getSchoolZip(),

sourceSchool.getSchoolTel());

}elseif(isCover) {

targetSchool.setSchoolCode(sourceSchool.getSchoolCode());

targetSchool.setSchoolName(sourceSchool.getSchoolName());

targetSchool.setProvinceCode(sourceSchool.getProvinceCode());

targetSchool.setSchoolAddress(sourceSchool.getSchoolAddress());

targetSchool.setSchoolZip(sourceSchool.getSchoolZip());

targetSchool.setSchoolTel(sourceSchool.getSchoolTel());

}

targetSchools.add(targetSchool);

}

syncService.saveOrUpdate(targetSchools);

}privatevoidsyncGrades() {

ListsourceGrades=getSourceGrades();

ListtargetGrades=newArrayList();

ListsourceGradeCodes=getGradeCodes(sourceGrades);

MaptargetGradeWithCodeMapping=gradeService.getGradeWithCodeMapping(sourceGradeCodes);for(Grade sourceGrade:sourceGrades) {

String gradeCode=sourceGrade.getGradeCode();

Grade targetGrade=targetGradeWithCodeMapping.get(gradeCode);if(targetGrade==null) {

targetGrade=newGrade(

sourceGrade.getGradeCode(),

sourceGrade.getName(),

sourceGrade.getEntranceDay(),

sourceGrade.getGraduateDay(),

sourceGrade.getSchoolCode(),

sourceGrade.getSchoolProperty());

}elseif(isCover) {

targetGrade.setGradeCode(sourceGrade.getGradeCode());

targetGrade.setName(sourceGrade.getName());

targetGrade.setEntranceDay(sourceGrade.getEntranceDay());

targetGrade.setGraduateDay(sourceGrade.getGraduateDay());

targetGrade.setSchoolCode(sourceGrade.getSchoolCode());

targetGrade.setSchoolProperty(sourceGrade.getSchoolProperty());

}

targetGrades.add(targetGrade);

}

syncService.saveOrUpdate(targetGrades);

}

当然,真实的代码更加复杂与混乱,但如果经过一系列重构,例如Rename Method,Extract Method之后,就会变得逐渐清晰,大体结构如上述展示的代码。阅读这样的代码,是否发现各个同步子方法均有似曾相识的感觉呢?究其原因,在于同步的执行逻辑大体相似,换言之,它们具有相似的模板。我们需要改善其结构,实现代码的重用。然而,在方法层面上,我们已很难实现这一点。事实上,当我们在编写同步方法时,已经落入了过程式设计的窠臼。我们首先想到的是执行的过程,而非对象。现在,我们需要将这些执行过程封装为对象,充分地利用继承等机制实现类级别的重用。显然,这里可以运用Form Template Method重构。当然,在此之前,我们还需要运用Extract Superclass,对School、Grade等类进行一系列重构,例如为它们建立共同的父类Entity,提供getCode()方法。并运用Rename Method,将原来各自实体类的相关方法,例如getSchoolCode()、getGradeCode()等,更名为getCode()。

现在,我们需要为同步操作定义一个共同的抽象类DataSynchronizer,然后利用Move Method重构,将原有SyncExecutor的相关代码搬移到DataSynchronizer中:

publicabstractclassDataSynchronizer {publicvoidexecute() {

ListsourceEntities=getSourceEntities();

ListtargetEntities=newArrayList();

ListsourceEntityCodes=getEntityCodes(sourceEntities);

MaptargetEntityWithCodeMapping=getEntityWithCodeMapping(sourceEntityCodes);for(Entity sourceEntity:sourceEntities) {

String entityCode=sourceEntity.getCode();

Entity targetEntity=targetEntityWithCodeMapping.get(entityCode);if(targetEntity==null) {

targetGrade=createEntity(sourceEntity);

}elseif(isCover) {

updateEntity(targetEntity,sourceEntity);

}

targetEntities.add(targetEntity);

}

syncService.saveOrUpdate(targetEntities);

}protectedabstractListgetSourceEntities();protectedabstractListgetEntityCodes(Listentities);protectedabstractMapgetEntityWithCodeMapping(ListentityCodes);protectedabstractEntity createEntity(Entity sourceEntity);protectedabstractvoidupdateEntity(Entity target, Entity source);

}

注意,在获得Entity与Code的Map对象时,我对原有的代码实现进行了封装,因为不同的实体同步类,所要调用的Service对象是不一样的。因此,需要将调用Service相关方法的实现留给子类。现在,只需要定义各个同步类继承DataSynchronizer,重写相关的受保护抽象方法即可:

publicclassSchoolSynchronizer extends DataSynchronizer{}publicclassGradeSynchronizer extends DataSynchronizer{}publicclassFacultySynchronizer extends DataSynchronizer{}

接着,修改SyncExecutor类的实现。为方便调用同步子类的相关方法,我定义了一个Factory Method:

publicclassSyncExecutor {publicvoidexecuteSync() {for(DataSynchronizer dataSync:createSynchronizers()) {

dataSync.execute();

}

}protectedListcreateSynchronizers() {

Listsynchronizers=newArrayList

synchronizers.add(newSchoolSynchronizer());

synchronizers.add(newGradeSynchronizer());

synchronizers.add(newFacultySynchronizer());returnsynchronizers;

}

}

以真正面向对象的方式来完成上述功能,无论在代码结构、重用性还是扩展性方面,比诸之前的实现,都有了长足的改善。这就是面向对象设计的优雅之处。

纵观整个重构过程,实际上,我在运用Convert Procedural Design to Objects重构时,大量运用了Rename Method、Extract Method、Move Method、Extract Superclass、Form Template Method等重构手法。这是合乎常情的。当我们在对程序进行重构时,往往需要运用各种重构手法,才能达到最终的重构目的。对于大型重构而言,这种特征尤其明显。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值