重构改善既有代码的设计-学习(六):处理继承关系

1、函数上移(Pull Up Method)

 

        无论何时,只要系统内出现重复,你就会面临“修改其中一个却未能修改另一个”的风险。通常,找出重复也有一定的难度。

        所以,某个函数在各个子类中的函数体都相同(它们很可能是通过复制粘贴得到的),这就需要使用函数上移,也就是将共同的函数上移到超类中

        函数上移过程中,被提升的函数可能会引用只出现于子类而不出现于超类的特性。此时,我就得用字段上移函数上移先将这些特性(类或者函数)提升到超类。 

2、字段上移(Pull Up Field) 

 

         如果各子类是分别开发的,或者是在重构过程中组合起来的,你常会发现它们拥有重复特性,特别是字段更容易重复。

        如果它们被使用的方式很相似,就可以将它们提升到超类中去。 

3、构造函数本体上移(Pull Up Constructor Body) 

 

        逐一移除子类间的公共代码,将其提升至超类构造函数中。对于公共代码中引用到的变量,将其作为参数传递给超类的构造函数。

        如果重构过程过于复杂,可以考虑转而使用以工厂函数取代构造函数(详见:重构改善既有代码的设计-学习(五):重构API-CSDN博客)。

4、函数下移(Push Down Method)

 

        如果超类中的某个函数只与一个(或少数几个)子类有关,那么最好将其从超类中挪走,放到真正关心它的子类中去。 

5、字段下移(Push Down Field) 

 

        如果某个字段只被一个子类(或者一小部分子类)用到,就将其搬移到需要该字段的子类中。 

6、以子类取代类型码(Replace Type Code with Subclasses) 

 

        软件系统经常使用类型码表现“相似但又不同的东西”。大多数时候,有这样的类型码就够了。但也有些时候,可以再多往前一步,引入子类。

        继承有两个诱人之处:

  1. 你可以用多态来处理条件逻辑。如果有几个函数都在根据类型码的取值采取不同的行为,多态就显得特别有用。引入子类之后,我可以用以多态取代条件表达式(详见:重构改善既有代码的设计-学习(四):简化条件逻辑-CSDN博客)来处理这些函数。 
  2. 有些字段或函数只对特定的类型码取值才有意义,此时可以创建子类,然后用字段下移把这样的字段放到合适的子类中去。

        例如:

function createEmployee(name, type) {
    return new Employee(name, type);
}

        改为:

function createEmployee(name, type) {
    switch (type) {
        case "engineer": return new Engineer(name);
        case "salesman": return new Salesman(name);
        case "manager": return new Manager (name);
    }
}

7、移除子类(Remove Subclass) 

 

        子类数据结构的多样和行为的多态提供支持,它们是针对差异编程的好工具。但随着软件的演化,子类所支持的变化可能会被搬移到别处,甚至完全去除,这时子类就失去了价值。有时添加子类是为了应对未来的功能,结果构想中的功能压根没被构造出来,或者用了另一种方式构造,使该子类不再被需要了。 

8、提炼超类(Extract Superclass)

 

         如果看见两个类在做相似的事,可以利用基本的继承机制把它们的相似之处提炼到超类

9、折叠继承体系(Collapse Hierarchy) 

 

         如果发现一个类与其超类已经没多大差别,不值得再作为独立的类存在,就需要把超类和子类合并起来

10、 以委托取代子类(Replace Subclass with Delegate)

 

        如果一个对象的行为有明显的类别之分,继承是很自然的表达方式。我可以把共用的数据和行为放在超类中,每个子类根据需要覆写部分特性。

        但继承也有其短板,他只能用于处理一个方向上的变化,并且继承给类之间引入了非常紧密的关系。在超类上做任何修改,都很可能破坏子类。

        用委托可以解决这两个问题。对于不同的变化原因,我可以委托给不同的类。与继承关系相比,使用委托关系时接口更清晰、耦合更少。

        可以用设计模式来理解本重构手法,就是用状态(State)模式或者策略(Strategy)模式
取代子类。这两个模式在结构上是相同的,都是由宿主对象把责任委托给另一个继承体系。

        例子:

class Order {
    get daysToShip() {
        return this._warehouse.daysToShip;
    }
}

class PriorityOrder extends Order {
    get daysToShip() {
        return this._priorityPlan.daysToShip;
    }
}

        改为:

class Order {
    get daysToShip() {
        return (this._priorityDelegate)
            ? this._priorityDelegate.daysToShip
            : this._warehouse.daysToShip;
    }
}

class PriorityOrderDelegate {
    get daysToShip() {
        return this._priorityPlan.daysToShip
    }
}

11、以委托取代超类(Replace Superclass with Delegate) 

 

        在对象技术发展早期,有一个经典的误用继承的例子:让栈(stack)继承列表(list)。这个想法的出发点是想复用列表类的数据存储和操作能力。虽说复用是一件好事,但这个继承关系有问题:列表类的所有操作都会出现在栈类的接口上,然而其中大部分操作对一个栈来说并不适用。更好的做法应该是把列表作为栈的字段,把必要的操作委派给列表就行了。 

         如果子类与超类之间的耦合过强,超类的变化很容易破坏子类的功能,此时就可以使用以委托取代超类。

        这样做的缺点就是,对于宿主类(也就是原来的子类)和委托类(也就是原来的超类)中原本一样的函数,现在我必须在宿主类中挨个编写转发函数。

        例子:

class List {...}
class Stack extends List {...}

        改为:

class Stack {
    constructor() {
        this._storage = new List();
    }
}
class List {...}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/354359.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MYSQL中group by分组查询的用法详解(where和having的区别)!

文章目录 前言一、数据准备二、使用实例1.如何显示每个部门的平均工资和最高工资2.显示每个部门的每种岗位的平均工资和最低工资3.显示平均工资低于2000的部门和它的平均工资4.having 和 where 的区别5.SQL查询中各个关键字的执行先后顺序 前言 在前面的文章中,我们…

指针的深入了解2

1.const修饰指针 在这之前我们还学过static修饰变量,那我们用const来修饰一下变量会有什么样的效果呢? 我们来看看: 我们可以看到编译器报错告诉我们a变成了一个不可修改的值,我们在变量前加上了const进行限制,但是我…

深入理解与防范C语言中的栈溢出问题

一、引言 栈溢出是计算机安全领域中一个常见的漏洞,特别是在C语言编程中。由于C语言的灵活性和对内存管理的直接操作性,如果程序员在编写代码时不注意,就可能导致栈溢出的发生。本文将全面解析栈溢出的概念、原因、影响以及防范措施。 二、…

绘制太极图 - 使用 PyQt

大家好!今天我们将一起来探讨一下如何使用PyQt,这是一个强大的Python库,来绘制一个传统的太极图。这个图案代表着古老的阴阳哲学,而我们的代码将以大白话的方式向你揭示它的奥秘。 PyQt:是什么鬼? 首先&a…

嵌入式——窗口看门狗(WWDG)补充

目录 一、独立看门狗与窗口看门狗 1.功能描述 2.两者区别 二、WWDG功能描述 1.窗口看门狗时钟 2.计数器时钟 3. 计数器 4.窗口值 三、WWDG超时时间 一、独立看门狗与窗口看门狗 1.功能描述 STM32有两个看门狗:一个是独立看门狗(IWDG&#xff0…

【GPU】GPU 硬件与 CUDA 程序开发工具

GPU 硬件与 CUDA 程序开发工具 笔记内容来自:《CUDA 编程:基础与实践》—樊哲勇 著 本文目录 GPU 硬件简介CUDA 程序开发工具CUDA 开发环境搭建用 nvidia-smi 检查与设置设备CUDA 的官方手册 GPU 硬件简介 GPU 是英文 graphics processing unit 的首字母…

【GitHub项目推荐--基于 AI 的口语训练平台】【转载】

Polyglot Polyglot 是一个开源的基于 AI 的口语训练平台客户端,可以在 Windows、Mac 上使用。 比如你想练习英语口语,只需在该平台配置一个虚拟的 AI 国外好友,你可以通过发语音的方式和 AI 好友交流,通过聊天的方式提升你的口…

黑马程序员——html css基础——day05——盒子模型

目录: 选择器 结构伪类选择器:nth-child(公式)伪元素选择器PxCook盒子模型 盒子模型-组成边框线 四个方向单方向边框线内边距尺寸计算外边距版心居中清除默认样式元素溢出外边距问题 合并现象外边距塌陷行内元素–内外边距问题圆角盒子阴影(拓展&#x…

【Java】Spring的APO及事务

今日目标 能够理解AOP的作用 能够完成AOP的入门案例 能够理解AOP的工作流程 能够说出AOP的五种通知类型 能够完成"测量业务层接口万次执行效率"案例 能够掌握Spring事务配置 一、AOP 1 AOP简介 问题导入 问题1:AOP的作用是什么? 问题2&am…

java设计模式:工厂模式

1:在平常的开发工作中,我们可能会用到不同的设计模式,合理的使用设计模式,可以提高开发效率,提高代码质量,提高系统的可拓展性,今天来简单聊聊工厂模式。 2:工厂模式是一种创建对象的…

HCIP-交换机实验

实验拓扑 实验需求 实验思路 配置IP地址 配置vlan 实验步骤 配置IP地址 以pc1为例&#xff1a; 配置vlan 以sw1为例&#xff1a; <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sys sw1 [sw1]vlan 3 Jan 28 2024 15:39:45-08:00 sw1 DS/…

HPE ProLiant MicroServer Gen8安装windows server 2019

按照《HP MicroServer Gen8使用官方工具安装Windows Sverver 2016教程》安装时&#xff0c;安装系统选项并没有server 2019可选&#xff0c;依然只是server 2012&#xff0c;我还以为是从单位拿回来的镜像有误&#xff0c;从官方下载了server 2019评估版&#xff0c;但依然只有…

【算法专题】二分查找(进阶)

&#x1f4d1;前言 本文主要是二分查找&#xff08;进阶&#xff09;的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日…

【UEFI实战】Redfish的BIOS实现——生成EDK数据

生成Redfish文件 Redfish数据的表示形式&#xff0c;最常用的是JSON。将JSON表示的数据转换成C语言可以操作的结构体&#xff0c;是必不可少的步骤。当然如果手动转换的话&#xff0c;需要浪费大量的时间&#xff0c;因此DMTF组织开发了一个工具&#xff0c;用于将JSON数据快速…

实验6:循环与子程序设计

1、实验目的&#xff1a; 通过完成将字节内存单元存储的8个数依次显示在屏幕上的程序设计&#xff0c;掌握循环与子程序设计的方法。 2、实验内容&#xff1a; 将内存单元存储的8个两位16进制数&#xff1a;01H, 25H, 38H, 62H, 8DH, 9AH, BAH, CEH依次显示在屏幕上。 3、实…

CSS设置单行文字水平垂直居中的方法

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>单行文字水平垂直居中</title><style>div {/* 给div设置宽高 */width: 400px;height: 200px;margin: 100px auto;background-color: red;/…

4.列表选择弹窗(CenterListPopup)

愿你出走半生,归来仍是少年&#xff01; 环境&#xff1a;.NET 7、MAUI 在屏幕中间弹窗的列表选择弹窗。 1.布局 <?xml version"1.0" encoding"utf-8" ?> <toolkit:Popup xmlns"http://schemas.microsoft.com/dotnet/2021/maui"x…

【学网攻】 第(12)节 -- 动态路由(RIP)

系列文章目录 目录 系列文章目录 文章目录 文章目录 前言 一、动态路由是什么&#xff1f; 二、实验 1.引入 总结 文章目录 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学网攻】 第(4…

【GitHub项目推荐--推荐一个开源的任务管理工具(仿X书/X钉)】【转载】

推荐一个开源的任务管理工具&#xff0c;该工具会提供各类文档协作功能、在线思维导图、在线流程图、项目管理、任务分发、即时 IM&#xff0c;文件管理等等。该开源项目使用到 Vue、Element-UI、ECharts 等技术栈。 开源地址&#xff1a;www.github.com/kuaifan/dootask 预览地…

linux基础学习(8):grep命令、通配符、管道符

1.grep命令 1.1命令格式 grep 选项 "搜索内容" 文件名 选项&#xff1a; -i&#xff1a;忽略大小写 -n&#xff1a;输出行号 -v&#xff1a;查找文件内不含搜索内容的部分 --colorauto&#xff1a;把搜索内容用不同颜色标注出来 1.2grep命令与find命令的区…