CH07_封装

2023-11-15

封装记录(Encapsulate Record | 162)

曾用名:以数据类代替记录(Replace Record with Data Class)

在这里插入图片描述

organization = {name: "Acme Gooseberries", country: "GB"};
class Organization {
    constructor(data) {
        this._name = data.name;
        this._country = data.country;
	}
    get name() {return this._name;}
    set name(arg) {this._name = arg;}
    get country() {return this._country;}
    set country(arg) {this._country = arg;}
}

动机

记录型结构是多数编程语言提供的一种常见特性。它们能直观的组织起存在关联的数据,可以将数据作为有意义的端元传递,而不仅是一堆数据的拼凑。但简单的记录型结构也有缺陷,需要清晰的区分“记录中存储的数据”和“通过计算得到的数据”。

对于可变数据,建议使用类对象,对象可以隐藏结构的细节,该对象的用户不必追究存储的细节和计算的过程,同时,这种封装还有助于字段的改名(外界通过访问函数来获取字段的值)。

记录型结构可以有两种类型:一种需要声明合法的字段名字,另一种可以随便用任何字段名字。后者常由语言库本身实现,并通过类的形式提供出来,这些类称为散列(hash)、映射(map)、散列映射(hashmap)、字典(dictionary)或关联数组(associative array)等。但使用这类结构也有缺陷,那就是一条记录上持有什么字段往往不够直观。

程序中间常常需要互相传递嵌套的列表(list)或散列映射结构,这些数据结构后续经常需要被序列化成JSON或XML。这样的嵌套结构同样值得封装,这样,如果后续其结构需要变更或者需要修改记录内的值,封装能更好地应对变化。

做法

  • 对持有记录的变量使用封装变量(132),将其封装到一个函数中。

  • 创建一个类,将记录包装起来,并将记录变量的值替换为该类的一个实例。然后在类上定义一个访问函数,用于返回原始的记录。修改封装变量的函数,令其使用这个访问函数。

  • 测试

  • 新建一个函数,让它返回该类的对象,而非那条元素的记录。

  • 对于该记录的每处使用点,将原先返回记录的函数调用替换为那个返回实例对象的函数调用。使用对象上的访问函数来获取数据的字段,如果该字段的访问函数还不存在,那就创建一个。每次更改之后运行测试。

    如果该记录比较复杂,例如是个嵌套解构,那么先重点关注客户端对数据的更新操作,对于读取操作可以考虑返回一个数据副本或只读的数据代理。

  • 移除类对元素记录的访问函数,那个容易搜索的返回原始数据的函数也要一并删除。

  • 测试

  • 如果记录中的字段本身也是复杂结构,考虑对其再次应用封装记录(162)或封装集合(170)手法。

封装集合(Encapsulate Collection | 170)

在这里插入图片描述

class Person {
    get courses(){return this._courses;}
    set courses(aList){this._courses-aList;}
    // ...
}
class Person {
    get courses(){return this.courses.slice();}
    addCourse(aCourse){...}
    removeCourse(aCourse){...}
    // ...
}

动机

封装程序中的所有可变数据,可以很容易看清楚数据被修改的地点和修改方式,需要更改数据结构时就非常方便。但封装集合时通常会犯一个错误:只对集合变量的访问进行了封装,但依然让取值函数返回集合本身。这使得集合的成员变量可以直接被修改,而封装它的类则全然不知,无法介入。为避免此种情况,可以在类上提供一些修改集合的方法——通常是“添加”和“移除”方法。

一种避免直接修改集合的方法是,永远不直接返回集合的值。这种方法提倡,不要直接使用集合的字段,而是通过定义类上的方法来代替。

还有一种方法是,以某种形式限制集合的访问权,只允许对集合进行读操作(比如,在Java中可以很容易地返回集合的一个只读代理)。

最常见的做法是,为集合提供一个取值函数,但令其返回一个集合的副本。这样即使有人修改了副本,被封装的集合也不会受到影响。

采用哪种方法并无定式,最重要的是在同个代码库中做法要保持一致。

做法

  • 如果集合的引用尚未被封装起来,先用封装变量(132)封装它
  • 在类上添加用于“添加集合元素”和“移除集合元素”的函数(如果存在对集合的设值函数,尽可能先用移除设值函数(331)移除它。如果不能移除该设值函数,至少让它返回集合的一个副本)
  • 执行静态检查
  • 查找集合的引用点。如果有调用者直接修改集合,令该处调用使用新的添加/移除元素的函数。每次修改后执行测试
  • 修改集合的取值函数,使其返回一份只读数据,可以使用只读代理或者数据副本。
  • 测试

以对象取代基本类型(Replace Primitive with Object | 174)

曾用名:以对象取代数据值(Replace Data Value with Object)

曾用名:以类取代类型码(Replace Type Code with Class)

在这里插入图片描述

orders.filter(o => "high" === o.priority || "rush" === o.priority);
orders.filter(o => o.priority.higherThan(new Priority("normal")))

动机

开发初期,往往决定以简单的数据项表示简单的情况,比如使用数字或字符串等。但随着开发的进行,可能会发现这些简单数据不再那么简单。

一旦发现随某个数据的操作不仅仅局限于打印时,可以为它创建一个新类。一开始这个类也许只是简单包装一下简单类型的数据,不过只要有了类,日后添加业务累哦及就简单多了。

做法

  • 如果变量尚未被封装起来,先使用封装变量(132)封装它。
  • 为这个数据值创建一个简单的类。类的构造函数应该保存这个数据值,并为它提供一个取值函数。
  • 执行静态检查。
  • 修改第一步得到的设值函数,令其创建一个新类的对象并将其存入字段,如果有必要的话,同时修改字段的类型声明
  • 修改取值函数,令其调用新类的取值函数,并返回结果。
  • 测试
  • 考虑对第一步得到的访问函数使用函数改名(124),以便更好反应其用途。
  • 考虑应用将引用对象改为值对象(252)或将值对象改为引用对象(256),明确指出先对象的角色是值对象还是引用对象。

以查询取代临时变量(Replace Temp with Query | 178)

在这里插入图片描述

const basePrice = this._quantity * this._itemPrice;
if (basePrice > 1000)
	return basePrice * 0.95;
else
	return basePrice * 0.98;
get basePrice() {this._quantity * this._itemPrice;}
...
if (this.basePrice() > 1000)
	return this.basePrice() * 0.95;
else
	return this.basePrice() * 0.98;

动机

临时变量的一个作用是保存某段代码的返回值,以便在函数的后面部分使用它。临时变量允许编程中引用之前的值,既能解释它的含义,还能避免对代码进行重复计算。但尽管使用变量很方便,很多时候还是值得更进一步,将它们抽取成函数。

抽取成函数能避免在多个函数中重复编写计算逻辑。

这项重构手法在类中施展效果最好,因为类为待提炼函数提供了一个共同的上下文。

以查询取代临时变量(178)手法只适用于处理某些类型的临时变量:那些只被计算一次且之后不再被修改的变量。

做法

  • 检查变量在使用前是否已经完全计算完毕,检查计算它的那段代码是否每次都能得到一样的值
  • 如果变量目前不是只读的,但是可以改造成为只读变量,那就先改造它。
  • 测试
  • 将为变量赋值的代码提炼成函数(确保待提炼函数没有副作用。若有,先应用将查询函数和修改函数分离(306)手法隔离副作用)
  • 测试
  • 应用内联变量(123)手法移除临时变量

提炼类(Extract Class |182 )

反向重构:内联类(186)

在这里插入图片描述

class Person {
    get officeAreaCode() {return this._officeAreaCode;}
    get officeNumber() {return this._officeNumber;}
}
class Person {
    get officeAreaCode() {return this._telephoneNumber.areaCode;}
    get officeNumber() {return this._telephoneNumber.number;}
}
class TelephoneNumber {
    get areaCode() {return this._areaCode;}
    get number() {return this._number;}
}

动机

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

维护一个有大量函数和数据的类,这样的类往往因为太大而不易理解。此时需要考虑哪些部分可以分离出去,并将它们分离到一个独立的类中。如果某些数据和某些函数总是一起出现,某些数据经常同时变化甚至彼此相依,这就表示应该将它们分离出去。

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

做法

  • 决定如何分解类所负的责任。
  • 创建一个新的类,用以表现从旧类中分离出来的责任(如果旧类剩下来的责任与旧类的名称不符合,为旧类改名)
  • 构造旧类时创建一个新类的实列,建立“从旧类访问新类”的连接关系
  • 对于想搬移的每一个字段,运用搬移字段(207)搬移之。每次更改后测试。
  • 使用搬移函数(198)将必要函数搬移到新类。先搬移较低层的函数(也就是“被其他函数调用”多于“调用其他函数”者)。每次更改后运行测试
  • 检查两个类的接口,去掉不再需要的函数,必要时为函数重新取一个合适新环境的名字
  • 决定是否公开新的类。如果确定需要,考虑新类应用将引用对象改为值对象(252)使其成为一个值对象

内联类(Inline Class | 186)

反向重构:提炼类(182)

在这里插入图片描述

class Person {
    get officeAreaCode() {return this._telephoneNumber.areaCode;}
    get officeNumber() {return this._telephoneNumber.number;}
}
class TelephoneNumber {
    get areaCode() {return this._areaCode;}
    get number() {return this._number;}
}
class Person {
    get officeAreaCode() {return this._officeAreaCode;}
    get officeNumber() {return this._officeNumber;}
}

动机

内联类正好与提炼类(182)相反。如果一个类不再承担足够责任,不再有单独存在的理由(这通常是因为此前的重构动作移走了这个类的责任),将这个类塞进另外一个类中。

应用这个手法的另一个场景是,手头有两个类,想重新安排它们肩负的职责,并让它们产生关联。这时发现先用本手法将它们内联成一个类再用提炼类(182)去分离其职责会更加简单。

做法

  • 对于待内联类(源类)中的所有public函数,在目标类上创建一个对应的函,新创建的所有函数应该直接委托至源类。
  • 修改袁磊public方法的所有引用点,令它们调用目标类对应的委托方法。每次更改后运行测试。
  • 将源类中的函数于数据全部搬移到目标类,每次修改之后进行测试,直到源类编程空壳为止。
  • 删除源类

隐藏委托关系(Hide Delegate | 189)

反向重构:移除中间人(192)

在这里插入图片描述

manager = aPerson.department.manager;
manager = aPerson.manager;
class Person {
	get manager() {return this.department.manager;}
}

动机

一个好的模块化的设计,“封装”是最关键特征之一。“封装”意味着每个模块都应该尽可能少了解系统的其他部分。一旦发生变化,需要了解这一变化的模块就会比较少,这会使变化比较容易进行。

如果某些客户端先通过服务对象的字段得到另一个对象(受托类),然后调用后者的函数,那么客户就必须知晓这一层委托关系。万一受托类修改了接口,变化会波及通过服务对象使用它的所有客户端。

做法

  • 对于每个委托关系中的函数,在服务对象端建立一个简单的委托函数。
  • 调整客户端,令它只调用服务对象提供的函数。每次调整后运行测试。
  • 如果将来不再有任何客户端需要取用Delegate(受托类),便可移除服务对象中的相关函数。
  • 测试。

移除中间人(Remove Middle Man | 192)

反向重构:隐藏委托关系(189)

在这里插入图片描述

manager = aPerson.manager;
class Person {
	get manager() {return this.department.manager;}
}
manager = aPerson.department.manager;

动机

“封装受托对象”这层封装也是有代价的。每当客户端要使用受托类的新特性时,你就必须在服务端添加一个简单委托函数。随着受托类的特性(功能)越来越多,更多的转发函数就会使人烦躁。服务类完全变成了一个中间人(81),此时就应该让客户直接调用受托类。

很难说什么程度的隐藏才是合适的,可以在系统运行过程中不断进行调整。

做法

  • 为受托对象创建一个取值函数。

  • 对于每个委托函数,让其客户端转为连续的访问函数调用。每次替换后运行测试

    替换完委托方法的所有调用点后,就可以删掉这个委托方法了。
    这能通过可自动化的重构手法来完成,可以先对受托字段使用封装变量(132),再应用内联函数(115)内联所有使用它的函数。

替换算法(Substitute Algorithm | 195)

在这里插入图片描述

function foundPerson(people) {
    for(let i = 0; i < people.length; i++) {
        if (people[i] === "Don") {
        	return "Don";
        }
        if (people[i] === "John") {
        	return "John";
        }
        if (people[i] === "Kent") {
        	return "Kent";
        }
    }
    return "";
}
function foundPerson(people) {
    const candidates = ["Don", "John", "Kent"];
    return people.find(p => candidates.includes(p)) || '';
}

动机

如果发现做一件事可以有更清晰的方式,就用比较清晰的方式取代复杂的方式。“重构”可以把一些复杂的东西分解为较简单的小块。

替换一个巨大且复杂的算法是非常困难的,只有先将它分解为较简单的小型函数,才能很有把握地进行算法替换工作。

做法

  • 整理一下待替换的算法,保证它已经被抽取到一个独立的函数中。
  • 先只为这个函数准备测试,以便固定它的行为。
  • 准备好另一个(替换用)算法。
  • 执行静态检查。
  • 运行测试,比对新旧算法的运行结果。如果测试通过,那就大功告成;否则,在后续测试和调试过程中,以旧算法为比较参照标准。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CH07_封装 的相关文章

  • 27.EI文章复现《高比例清洁能源接入下计及需求响应的配电网重构》

    下载地址 高比例清洁能源接入下计及需求响应的配电网重构 1主要内容 该程序复现 高比例清洁能源接入下计及需求响应的配电网重构 以考虑网损成本 弃风弃光成本和开关操作惩罚成本的综合成本最小为目标 针对配电网重构模型的非凸性 引入中间变量并对其
  • 经典场效应管如何快速关断技巧-KIA MOS管

    mos管的快速关断原理 R4是Q1的导通电阻没有Q1就没有安装的必要了 当低电位来时Q1为泻放扩流管 功率MOS管怎样关断 能否用PWM实现 怎样实现 功率mosfet的三个端口 G极 D极 S极 G极控制mosfet的开通 关断 给GS极
  • 关于互联网思维与技术团队的一些总结

    2017 7 4更 真正在底层工作的人员 跟站在高层的人看到的东西都是两个东西 真正的从底层走到高层才能看的更精准 同样的 从底层走到高层的人 也没有一直处在高层的远见与见识 我信奉公司处于什么阶段用什么样的人 没必要一开始就弄高精尖的人和
  • iOS项目技巧+封装过程

    前言 接手一个外包项目 发现问题颇多 下面是对整个项目封装过程的记录 当前项目存在的问题 1 接口前缀太多 切换环境不方便 2 通用方法没有进行封装 gt 支付方法哪里用到写哪里 3 扩展性和容错率太低 许多数组取值是直接根据数组下标来取的
  • Java实体类中封装其他实体类并引用

    在Java开发过程中有很多情况是二个表及以上的联合操作 这是需要分清楚表的主次关系 在引用的时候有人会把二个表的数据全都封装在一个实体类中 然后在对这个实体类进行操作 但如果是三个表呢 四个表呢 还都封装在一个实体类吗 这样被封装的实体类的
  • 震惊,微信小程序可以设置网络字体!真香

    准备工作 获取字体链接 还原设计稿的时候需要用到如下特殊字体 google 的 Montserrat https fonts google com specimen Montserrat 选择这个字体 下载全部字体 将本地的字体文件上传到自
  • JS 函数

    JS 函数 关键字形式的函数
  • Easyx-----c++实现经典Windows扫雷

    一些说明 关于扫雷的基本实现 我在这篇博客已经详细介绍Easyx c语言实现简易版扫雷 考拉爱睡觉鸭 的博客 CSDN博客 这里不再描述 主要是以c 单例设计模式的方式实现扫雷 多加了右键点击笑脸作弊功能 不会扫雷的小伙伴也可以愉快玩耍了
  • R语言与面向对象的编程(3):R6类

    专注系列化 高质量的R语言教程 本号已支持快捷转载 无需白名单即可转载 本系列将介绍R语言中三个与面向对象的编程 Object Oriented Programming OOP 相关的工具包 proto R6和基础包methods 这是一个
  • 一个重构:开闭原则案例

    原始代码 public class Alert private AlertRule rule private Notification notification public Alert AlertRule rule Notificatio
  • 代码坏味道与重构之重复代码

    文章目录 1 重复代码的特征 2 重复代码的影响 3 重复代码的重构技巧 1 重复代码的特征 重复代码是代码坏味道的典型代表 重复代码是指相同或相似的代码在一个以上的地方出现 通常有以下几种情形 同一个类 多个方法间重复 子类之间代码重复
  • 重构-提取重复的代码

    在编写程序过程中 特别是刚刚入行没有多久的程序员 经常会犯的一个错误就是大段大段的复制粘贴代码 把功能相近的代码直接复制过来而不加以修改 这个习惯也许来源于你的老师也许来源于你本身的原因 总之 对于这一类程序员最好的设计模式就是 Ctrl
  • python学习日记【13 - 面向对象三】

    面向对象三 继承简介 方法重写 super 多重继承 多态 属性和方法 继承简介 继承是面向对象三大特性之一 通过继承我们可以使一个类获取到其他类中的属性和方法 在定义类时 可以在类名后面的括号中指定当前类的父类 超类 基类 继承提高了类的
  • 如何提升项目管理过程中测试阶段的工作效率?

    按照测试阶段划分 分析需求 评审 方案制定 用例设计 用例执行 验收 报告 1 需求了解阶段 测试人员应该是最熟悉需求的人 甚至高于产品和业务 应该是对所测系统中细节 逻辑 真实情况最了解的人 没有之一 需求评审 了解阶段 多提出建设性的意
  • 主动配电网SOCP_OPF学习笔记(4)配电网重构

    配电网中的开关一般可分为联络开关和分段开关 联络开关负责转供备用和网络结构优化 常开 分段开关用于连接两条线路段的开关 为常闭 通过改变这两种开关的状态来调整网络拓扑结构 称为网络重构 加入联络开关支路会形成弱环网 1 辐射状拓扑约束 为了
  • 预见未来:超强元AI诞生,抓住这个机会,利用AI变现也变得更加容易

    目录 一 引言 二 介绍 三 技术展现 四 元AI架构图展现 五 元AI变现技巧 商业版说明 六 后期规划 一 引言 如何利用AI变现已经成为了当今各个行业亟需解决的问题 随着人工智能技术的快速发展和普及 越来越多的企业开始将其应用于产品研
  • 领域驱动设计:DDD重构中台业务模型

    文章目录 如何避免重复造轮子 如何构建中台业务模型 如何避免重复造轮子 要避免重复建设 就要理解中台的理念和思想 中台是企业级能力复用平台 复用 用白话说就是重复使用 就是要避免重复造轮子的事情 中台的设计思想与 高内聚 低耦合 的设计原则
  • python自动化笔记(十一)——openpyxl之封装

    封装一个可以读取任意excel文件的方法 可以指定读取的表单 当我们多次从excel中读取数据时 就不用重复地写代码 只需调用封装的类即可 一 封装的excel类实现的需求是什么 1 读取表头数据 2 读取表头以外的所有数据 返回值 列表
  • 【封装】实体类(entity)

    实体类entity 一 ORM 1 1 ORM 实体类 entity 零散数据的载体 1 1 1 ORM应用 一 ORM ORM Object Relational Mapping 从数据库查询到的结果集 ResultSet 在进行遍历时
  • 目标检测算法改进系列之添加SCConv空间和通道重构卷积

    SCConv 空间和通道重构卷积 SCConv 空间和通道重构卷积 的高效卷积模块 以减少卷积神经网络 CNN 中的空间和通道冗余 SCConv旨在通过优化特征提取过程 减少计算资源消耗并提高网络性能 该模块包括两个单元 1 空间重构单元

随机推荐

  • webpack5 基础配置(7) eslint-ts的使用和在webpack中的配置 加载vue文件

    上一节最后讲到了typescript的使用 ts loader本质上也是利用与tsc 所以安装ts loader的同时需要安装typescript 如果你没安装typescript 在你安装ts loader的时候 会根据ts loader
  • Git回退分支到某版本

    1 找到要回退的版本号 TortoiseGit gt Show Log gt 选中要回退的版本 gt Reset xxx to this gt commit旁复制版本号 2 本地回退到某版本 git reset hard 9224ad994
  • Idea 中 Docker 的 log 乱码

    IDEA 本地调试代码中英文显示全部正常 但是用 idea 中的 docker 插件部署到服务器 再查看 容器中 log 的时候 log 里面的中文全是乱码 就开启了一段排查过程 开始一个个排查 程序员的日常 查看容器中语言 字符集 环境
  • 【Android】java.lang.UnsatisfiedLinkError: No implementation found for void xx xx xx -- 问题解决

    Android在开发过程中总会出现各种各样的bug 要想畅通无阻的完成一个app的 开发工作固然有点难度 这不 我的程序跑着跑着又报错了 AndroidRuntime FATAL EXCEPTION Thread 4903 Process
  • 反汇编二进制代码

    最近又做了一些内核hook的工作 繁琐的地方在于二进制指令的可读性上 下面简要记录dump出指令二进制 之后利用binutils来转成可读的汇编代码 hook的主要流程参考之前的linux内核态hook模块 splice 主要就是构建一个t
  • 理解MySQL回表

    回表就是先通过数据库索引扫描出数据所在的行 再通过行主键id取出索引中未提供的数据 即基于非主键索引的查询需要多扫描一棵索引树 因此 可以通过索引先查询出id字段 再通过主键id字段 查询行中的字段数据 即通过再次查询提供MySQL查询速度
  • Java编程——输出1000以内的素数(质数)

    素数的定义是什么 质数 prime number 又称素数 有无限个 一个大于1的自然数 除了1和它本身外 不能被其他自然数 质数 整除 换句话说就是该数除了1和它本身以外不再有其他的因数 否则称为合数 public class demo7
  • STM32库函数TIM_SetCompare()的工作机制测试

    一 TIM SetCompare 函数的定义 其中 TIM SetCompareX 这个函数有四个 它们为 TIM SetCompare1 TIM SetCompare2 TIM SetCompare3 TIM SetCompare4 同时
  • 引脚悬空是什么电平_STM32单片机必须掌握的八种IO口模式和引脚配置方式

    八种IO口模式 STM32有八种IO口模式 分别是 模拟输入 浮空输入 上拉输入 下拉输入 开漏输出 推挽输出 复用开漏输出和复用推挽输出 1 模拟输入 GPIO Mode AIN模拟输入 即关闭施密特触发器 将电压信号传送到片上外设模块
  • 关于STM32F103 TIM2重映射

    关于STM32F103 TIM2重映射 如何使用重映射和如何重映射为哪些管脚 这里不详细讲解 可以百度找到 下面讲的是tim2重映射为PA15 PB3 PB10 PB11 这里的设置网上也有讲解 但是如果功能较为复杂的程序 外设用的比较多的
  • 黑马JVM总结(五)

    1 方法区 它是所有java虚拟机 线程共享的区 存储着跟类的结构相关的信息 类的成员变量 方法数据 成员方法 构造器方法 特殊方法 类的构造器 方法区在虚拟机启动时被创建 方法区逻辑上是堆的组成部分 但是不同的JVM厂商实现是不一样的 O
  • 进程,线程,协程总结

    进程 三种状态 就绪态 运行的条件都已经慢去 正在等在cpu执行 执行态 cpu正在执行其功能 等待态 等待某些 条件满足 例如一个程序sleep了 此时就处于等待态 生命周期 用户编写代码 代码本身是以进程运行的 启动程序 进入进程 就绪
  • Eclipse搭建stm32+jlink开发环境全攻略

    Eclipse搭建stm32 jlink开发环境全攻略 初级篇 前言 为什么需要这样的开发环境 免费 跨平台 自由度高 Eclipse代码提示功能强大 MDK弱爆了 注 本人原创 转载注明作者 by 秋之前 email xia mengli
  • paddleOCR踩坑记

    paddleOCR踩坑记 训练莫名终止或者评估莫名终止 训练和评估的效果都特别好 预测的效果却特别差 使用gen label py报错 将paddleOCR转成pytorch框架 训练莫名终止或者评估莫名终止 这是因为在tools prog
  • 2023全国大学生数学建模竞赛B题思路模型代码

    目录 一 选题建议先发布 思路模型代码论文第一时间更新 获取见文末名片 二 选题建议 后续思路代码论文 B 题 多波束测线问题 各题分析 获取完整思路代码见此处名片 一 选题建议先发布 思路模型代码论文第一时间更新 获取见文末名片 二 选题
  • python使用matplotlib:subplot绘制多个子图

    CSDN GitHub python使用matplotlib subplot绘制多个子图 AderXCoding language python matplotlib subplot 转自 https blog csdn net gatie
  • 解决eclipse启动报错问题:Could not create the Java Virtual Machine...

    电脑重装系统后 下了很多软件 其中就包括eclipse 但是在安装好后打开eclipse时报错 点击确定出现下面这样 网上找了原因 是因为自己在安装JDK的时候在C windows System32文件中生成了三个文件java exe ja
  • vue.js 开发环境搭建最简单攻略

    更新 本篇文章是我很之前写的 对于一些没有工作 或者js基础不太好的同学 建议不必大费周章去搭建环境 可以直接引用 vue js 就可以进行学习 练习 有些过程是水到渠成的 当初很多不懂的东西慢慢就懂了 官方指南假设你已有HTML CSS和
  • 小学数学题的Java实现

    昨天 去朋友家一起做饭 刚好有小孩问我问题 说你不是学计算机的吗 那你教我做一道数学题 我刚开始看的时候愣了一下 不过 想了一会还是解决 题目是这样的 有一袋糖果 每次从袋子里面拿走一半又放进袋子一颗 经过5次操作后 袋子还剩余4颗糖果 请
  • CH07_封装

    封装记录 Encapsulate Record 162 曾用名 以数据类代替记录 Replace Record with Data Class organization name Acme Gooseberries country GB c