《重构改善既有代码的设计》之重构列表--在对象之间搬移特性(二)

2023-12-16 14:58

本文主要是介绍《重构改善既有代码的设计》之重构列表--在对象之间搬移特性(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

三、Extract Class (提炼类)

某个类做了应该由两个类做的事。

建立一个新类,将相关的字段和函数从旧类搬移到新类。

动机

你也许听过类似的教诲:一个类应该是一个清楚的抽象,处理一些明确的责任。但是在实际工作中,类会不断成长扩展。你会在这儿加入一些功能,在那儿加一些数据。给某个类添加一项新责任时,你会觉得不值得为这项责任分离出一个单独的类。于是,随着责任的不断增加,这个类会变得过分复杂。很快,你的类就会变成一团乱麻。

另一个往往在开发后期出现的信号是类的子类化方式。如果你发现子类化只影响类的部分特性,或如果你发现某些特性需要以一种方式来子类化,某些特性则需以另一种方式子类化,这就意味你需要分解原来的类。

做法

1、决定如何分解类所负的责任。

2、建立一个新类,用以表现从旧类中分离出来的责任。

3、建立“从旧类访问新类”的连接关系。

有可能需要一个双向连接。但是在真正需要它之前,不要建立“从新类通往旧类”的连接。

4、对于你想搬移的每一个字段,运用Move Field搬移之。

5、每次搬移后,编译、测试。

6、使用Move Method将必要函数搬移到新类。新搬移较低层函数(也就是“被其他函数调用”多于“调用其他函数”者),再搬移叫高层函数。

7、每次搬移之后,编译、测试。

8、检查,精简每个类的接口。

如果你建立起双向连接,检查是否可以将它改为单向连接。

9、决定是否公开新类。如果你确定需要公开它,就要决定让它成为应用对象还是不可变的值对象。

四、Class(将类内联化)

某个类没有做太多事情。

将这个类的所有特性搬移到另一个类中,然后移除原类。

动机

Inline Class 正好与Extract Class 相反。如果一个类不再承担足够责任,不再有单独存在的理由(这通常是因为此前的重构动作移走了这个类的责任)我就会挑选这一“萎缩类”的最频繁用户(也是个类),以Inline Class 手法将“萎缩类”塞进另一个类中。

做法

1、在目标类身上声明源类的public 协议,并将其中所有函数委托至源类。

如果“以一个独立接口表示源类函数”更合适的话,就应该在内联之前先使用Extract Interface 

2、修改所有源类引用点,改而引用目标类。

将源类声明为private,以斩断包之外的所有引用可能。同时修改源类的名称,这便可使编译器帮助你捕捉到所有对于源类的隐藏引用点。

3、编译、测试。

4、运用Move MethodMove Field,将源类的特性全部搬移到目标类。

5、为源类举行一个简单的“丧礼”。

五、Hide Delegate(隐藏“委托关系”)

客户通过一个委托类来调用另一个对象。

在服务类上建立客户所需的所有函数,用以隐藏委托关系。

动机

“封装”即使不是对象的最关键特征,也是最关键特征之一。“封装”意味着每个对象都应该尽可能少了解系统的其他部分。如此一来,一旦发生变化,需要了解这一变化的对象就会比较少--这会使变化比较容易进行。

如果某个客户先通过服务对象的字段得到两一个对象,然后调用后者的函数,那么客户就必须知晓这一层委托关系。万一委托关系发生变化,客户也得相应变化。你可以在服务对象上放置一个简单的委托函数,将委托关系隐藏起来,从而去除这种依赖。这么一来,即便发生委托关系上的变化,变化也将限制在服务对象中,不会波及客户。

做法

1、对于每一个委托关系中的函数,在服务对象端建立一个简单的委托函数。

2、调整客户,令它只调用服务对象提供的函数。

如果使用者和服务提供者不在同一个包,考虑修改委托函数的访问权限,让客户得以在包外调用它。

3、每次调整后,编译、测试。

4、如果将来不再有客户需要取用的Delegate(受托类),便可移除访问对象中的相关访问函数。

5、编译、测试。

这篇关于《重构改善既有代码的设计》之重构列表--在对象之间搬移特性(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/500878

相关文章

Javaee多线程之进程和线程之间的区别和联系(最新整理)

《Javaee多线程之进程和线程之间的区别和联系(最新整理)》进程是资源分配单位,线程是调度执行单位,共享资源更高效,创建线程五种方式:继承Thread、Runnable接口、匿名类、lambda,r... 目录进程和线程进程线程进程和线程的区别创建线程的五种写法继承Thread,重写run实现Runnab

Python中将嵌套列表扁平化的多种实现方法

《Python中将嵌套列表扁平化的多种实现方法》在Python编程中,我们常常会遇到需要将嵌套列表(即列表中包含列表)转换为一个一维的扁平列表的需求,本文将给大家介绍了多种实现这一目标的方法,需要的朋... 目录python中将嵌套列表扁平化的方法技术背景实现步骤1. 使用嵌套列表推导式2. 使用itert

C# 比较两个list 之间元素差异的常用方法

《C#比较两个list之间元素差异的常用方法》:本文主要介绍C#比较两个list之间元素差异,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. 使用Except方法2. 使用Except的逆操作3. 使用LINQ的Join,GroupJoin

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

深度解析Java项目中包和包之间的联系

《深度解析Java项目中包和包之间的联系》文章浏览阅读850次,点赞13次,收藏8次。本文详细介绍了Java分层架构中的几个关键包:DTO、Controller、Service和Mapper。_jav... 目录前言一、各大包1.DTO1.1、DTO的核心用途1.2. DTO与实体类(Entity)的区别1

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

Java中调用数据库存储过程的示例代码

《Java中调用数据库存储过程的示例代码》本文介绍Java通过JDBC调用数据库存储过程的方法,涵盖参数类型、执行步骤及数据库差异,需注意异常处理与资源管理,以优化性能并实现复杂业务逻辑,感兴趣的朋友... 目录一、存储过程概述二、Java调用存储过程的基本javascript步骤三、Java调用存储过程示

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码