整体过程
1) 原代码重构成逻辑块清晰的过程化代码
2) 对不同逻辑块进行抽取成服务类
3) 从领域对象的角度分析服务类,通过单一职责来梳理服务类
(二)原代码重构成逻辑块清晰的过程化代码
每个逻辑块要有明确的输入输出,不同逻辑块最好能做到无序,如果一定有有序,要对有序有地方有所注释。每下个逻辑块都很分明,想抽成方法就可以随时抽取,不想抽取也可以保持现状,当重复代码出现时要进行抽取。如下是个合格的过程化代码示例。
返回值 方法1(参数1,参数2){
返回值变量1; //声明方法返回值
//逻辑块A
跨块变量AB1;//被多个逻辑块使用
块变量声明A1;
块变量声明A1=块代码A0(参数1);
跨块变量AB1=块代码A1( 块变量声明A1 ,参数2);
局部结果1=XXXX;
返回值变量1 =XXXXX( 局部结果1 );
//逻辑块BCD....
//方法返回值
}
逻辑块的输入和输出:
输入:方法返回值,方法参数,跨块变量,类变量
输出:逻辑块变量,方法返回值,方法参数(很少),跨块变量,类变量
逻辑块变量:只在一个逻辑块中新建和使用的变量,在逻辑块抽取成新方法时,随逻辑块迁徙走就好,属于逻辑块的内在逻辑。不是逻辑块的输入,但可以是逻辑块的输出。
方法返回值:在方法的第一句中进行声明,在最后一句返回。不同逻辑块和返回值可以有两种形式联系,1.返回值即不是逻辑块的输入也不是逻辑声的输出最好,逻辑块有自己的输入和输出。逻辑块的输出再去反映到方法返回值上(比如,如果是计数,每个逻辑块返回自己的计数,再累加到返回值上)。2.有时为了简便,方法返回值直接传入不同的逻辑块中,逻辑块直接对返回值对象进行改变,这样会形成返回值同时是不同逻辑块的输入和输出参数,抽取逻辑块时会使用方法参数来做为返回值。
方法参数:一般做为整个方法的输入,耦合程度仅限于方法,耦合小。线程未必安全。在方法需要不只一个返回值时,也会用于输出。也可能会同时是输入和输出。但逻辑块很少以方法参数做为输出。
跨块变量:可以在多个逻辑块内使用的变量。可以做为逻辑块的输入和输出。一般做为上一个逻辑块的输出和下一个逻辑块的输入,是不同逻辑块的桥梁。跨块变量的引入会形成不同逻辑块的顺序依赖,跨块变量能取消就取消。
类变量:可以做为不同逻辑块的输入和输出,可以承担上述任何变量的责任。
(三)对不同逻辑块进行抽取成服务类:
输入成为方法参数,如果输入比较多,可以把输入对象化(即用一个类结构来包含多个输入)。
输出成为方法返回值或者输出参数。如果输出比较多,可以把输出对象化。
根据逻辑块的业务复杂度来决定是把逻辑块抽取的方法是放入已经的类,还是新建立的类中。心中知道了程序有多个逻辑要处理,才能去思考有多少逻辑实体。本质上还是要分析程序做了几件事。
class 返回值A{
跨块变量AB1;//被多个逻辑块使用
局部结果1=XXXX;
}
AImpl{ //省去了接口
返回值A 方法(参数1,参数2){
//逻辑块A
返回值A;
块变量声明A1;
块变量声明A1=块代码A0(参数1);
返回值A.跨块变量AB1=块代码A1( 块变量声明A1 ,参数2);
返回值A. 局部结果1=XXXX;
return 返回值A;
}
}
原方法演变成
AImpl aservice;
返回值 方法1(参数1,参数2){
返回值变量1; //声明方法返回值
//逻辑块A
返回值A =aservice.方法(参数1,参数2);
返回值变量1 =XXXXX(返回值A .局部结果1);
//逻辑块BCD....
返回值变量1. 跨块变量AB1可以被引用
//方法返回值
}
(四)从领域对象的角度分析服务类,通过单一职责来梳理服务类
软件的构成
首先对软件的认识上,软件是要解决问题的,要建立软件是做了很重要事情的认识,这个很重要的事情才是软件的核心,而不是这中间涉及的技术。
构建一个软件时,想好了软件是解决了哪个重大的问题,解决这个重大问题时,需要一些第三方的协助,需要把结果反馈给别人。故软件从结构上有三部分组成,1.解决问题的逻辑。2.需要协助的第三方。3.需要使用问题答案的第三方。第2和第3都是通过技术手段取得一些东西。重点就在于要解决问题的逻辑这一部分。
重视业务-从业务角度松耦合
解决问题的逻辑部分的设计,就成了软件的核心设计,这个设计其实就是一个执行方案,所谓设计的好坏更多的是对我们人来说,当问题变化时,怎么样能更容易的让原有的设计支持到新的需求。如果能把原问题分割成比较小的逻辑块,不同逻辑块之间松耦合,就能在变化时只变动其中的某些逻辑块。
领域对象梳理-抽象
有了松耦合的逻辑块,大体意思是对了,也可以按这个进行编程了。
要想做到更好的维护,就需要把这些逻辑块梳理成职责分明的协作工人,每个逻辑块都有着明确而单一的职责,每个人做好自己的事,并信任的使用其它人提供的服务。这时就需要对逻辑块按单一职责进行命名,并分析他们间的关系。每个工人都有一个职责列表,也就是接口。
相关推荐
在重构过程中,单元测试是必不可少的安全网。通过编写测试用例来确保代码的功能不变,开发者可以放心地进行修改。本章可能还会涉及如何创建和运行这些测试,以及如何使用测试驱动开发(TDD)的原则来指导重构。 ...
过程重构的生命周期方法论 过程重构的生命周期方法论是指在业务流程再造(BPR)项目中应用的方法论,是在对主要BPR方法的阶段、任务和技术的分析与综合的基础上建立的。其主要目标是重塑企业业务流程,提高企业的...
通过这些测试,可以确保重构过程中的代码质量不会下降,同时也能在早期发现和修复潜在问题。 此外,重构还包括对函数的重新组织,如提炼函数(Extract Method)以提取重复代码,或将小函数内联化(Inline Method)...
书中也强调了编写单元测试的重要性,单元测试不仅可以确保重构过程不会破坏现有的功能,还可以作为重构后的代码质量保证。 管理重构的风险也是《重构与模式》讨论的重要内容之一。重构可能会引入新的错误,增加系统...
这个压缩包文件“代码重构源码(包含重构前后代码)”提供了面向对象编程领域中的一个实例,具体是对影片出租店租赁程序的重构过程。通过对原始代码(First_Instance_Original)进行分析和改进,我们可以深入理解...
1. **长方法**:如果一个方法执行多个职责,应考虑拆分为多个小方法,每个方法只做一件事。 2. **重复代码**:重复的代码不仅浪费存储空间,也增加了维护成本。通过创建函数或类来实现代码复用。 3. **过长的参数...
这本书详细阐述了重构过程中的一系列模式,帮助开发者更好地理解和实践重构。 在面向对象编程中,重构通常是为了消除代码异味(Code Smell),这些异味可能是冗余代码、过长函数、复杂的条件表达式等。通过对这些...
重构是软件开发过程中的一个重要环节,与新功能的实现同样重要。 随着软件开发的持续进行,代码库可能会不断增长,这就导致了代码变得越来越复杂,难以管理和维护。代码的复杂性往往隐藏着潜在的错误和缺陷,使得新...
书中强调了单元测试和集成测试的作用,以及如何在重构过程中有效地利用它们。 6. **案例研究**:书中可能包含真实世界的案例,展示了如何在实际项目中实施重构,让读者能够更好地理解和应用理论知识。 7. **代码...
8. **重构测试**:在重构过程中,持续运行单元测试以确保每次修改后功能未受影响。这是重构过程中的安全网,防止引入新的错误。 此外,"refactoring-demo"可能是一个代码示例,用于配合PPT展示实际的重构过程。读者...
1. **识别坏味道**:通过识别代码中的“坏味道”(如过长函数、重复代码、复杂的条件表达式等)来确定需要重构的部分。 2. **小步前进**:每次重构都应进行小规模的改动,并频繁地运行测试,确保代码的行为未被改变...
功能型重构关注于软件的功能,例如拆分长方法、合并重复代码等。非功能型重构则更关注于软件的性能、安全性、可用性等方面,比如数据库重构、接口重构等。 软件重构的关键知识点包括以下几个方面: 1. 重构的意义...
识别并消除这些臭味是重构的关键步骤,比如过长方法、重复代码、开关语句等。作者可能会提供识别和修复这些代码臭味的方法。 4. **步骤与策略**:书中会详细阐述从重构到模式的步骤和策略,包括如何选择合适的重构...
这些书籍提供了丰富的重构模式和步骤,帮助开发者在实践中避免常见的陷阱,确保重构过程的安全性。 在压缩包的文件名称列表中提到的 "prog",可能是指程序或编程相关的文件。在实际学习过程中,我们可以打开这些...
通过编写自我测试的代码和使用测试框架(如JUnit)可以确保重构过程中不会引入新的错误,并且鼓励开发者增加测试用例以覆盖更多可能的情况。 具体到重构技术的操作,讲义中介绍了众多实用的重构手法,包括提炼函数...
- **发现和修复缺陷**:重构过程中,通过对代码结构的梳理,可以更容易发现潜在的问题。 - **提高编程速度**:优化过的代码结构可以提高开发人员的工作效率,减少未来修改和扩展时的时间消耗。 3. **何时进行重构...
- **实施结果**:重构过程耗时长且成本高昂,最终发现Zope3并不像预期那样完美,反而带来了更多的问题。 - **反思总结**:从这次经历中学到了宝贵的经验教训,例如不应盲目追随新技术潮流,而应根据实际情况做出决策...