




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、扬帆起航圈复杂度圈复杂度Cyclomatic Complexity is 17 (max allowed is 7).Cyclomatic Complexity is X (max allowed is X) 我的QQ:28797575知道做什么吗?文档示例 无目录 有目录不聚焦不知道目标,不知道总体结构不知道是否合理没有层次是否有遗漏带来时间成本质量问题4知道做什么吗? QQ: 28797575圈复杂度 概念概念概念计算方法计算方法检查工具检查工具二二不不二二重构方法重构方法案例分析案例分析McCabe复杂度圈复杂度圈复杂度基本复杂度基本复杂度模块设计复杂度模块设计复杂度设计复杂度设计复杂度
2、集成复杂度集成复杂度行数行数全局数据复杂度全局数据复杂度局部数据复杂度局部数据复杂度病态数据复杂度病态数据复杂度规范化复杂度规范化复杂度框架群:181124238 我的QQ:307087558(1)圈复杂度(Cyclomatic Complexity (v(G) )l概念圈复杂度是用来衡量一个模块判定结构的复杂程度,数量上表现为独立路径的条数。l计算方法如果一个模块流程图有e条边n个节点, 它的圈复杂度v(G)=e-n+2。 QQ: 28797575 圈复杂度(Cyclomatic Complexity)是一种代码复杂度的衡量标准。它可以用来衡量一个模块判定结构的复杂程度,数量上表现为独立线性
3、路径条数,也可理解为覆盖所有的可能情况最少使用的测试用例数。圈复杂度大说明程序代码的判断逻辑复杂,可能质量低且难于测试和维护。程序的可能错误和高的圈复杂度有着很大关系。 圈复杂度主要与分支语句(if、else、switch 、for等)的个数成正相关。当一段代码中含有较多的分支语句,其逻辑复杂程度就会增加。什么是圈复杂度 QQ: 28797575示例下面这个实例中,单元测试的覆盖率可以达到100%,但是很容易发现这其中已经漏掉了一个NPE的测试用例。case1方法的圈复杂度为2,因此至少需要2个用例才能完全覆盖到其所有的可能情况。/程序原代码,圈复杂度为 2public String case
4、1(int num) String string = null; if (num = 1) string = String; return string.substring(0);/上面代码的单元测试代码public void testCase1() String test1 = case1(1); 圈复杂度主要与分支语句(if、else、,switch 等)的个数成正相关。当一段代码中含有较多的分支语句,其逻辑复杂程度就会增加。 QQ: QQ: 28797575圈复杂度 计算概念概念计算方法计算方法检查工具检查工具二不二二不二重构方法重构方法案例分析案例分析 QQ: 28797575示例 如
5、果一个模块流程如下有e条边n个节点,它的圈复杂度v(G) = e-n+2 例: QQ: 28797575圈复杂度的计算 圈复杂度(cyclomatic complexity): M = E N + 2P E: 边的数量 N: 节点的数量 P: 分离部分的数量,一般为1,都是联通的 圈数(cyclomatic number): M = E N + P E,N,P参数同上 圈复杂度和圈数之间的关系为: 对有向图A,将A的每个出口(exit)与相应的入口(entrance)相连得到有向图B,则A的圈复杂度与B的圈数相等 圈复杂度又叫做CC复杂度,也可能被称为循环复杂度,它表达的是if . then
6、. else ., swith . case ., 循环语句等分支语句造成的程序控制流复杂程度 QQ: 28797575计算公式补充 通常使用的计算公式是V(G) = e n + 2 , e 代表在控制流图中的边的数量(对应代码中顺序结构的部分),n 代表在控制流图中的节点数量,包括起点和终点(1、所有终点只计算一次,即便有多个return或者throw;2、节点对应代码中的分支语句)。 QQ: 28797575 例如下图示例一个单入口、单出口的程序图(不是结构化程序图),其圈复杂度为10-7+2=5: 从节点G到A添加一条有向边,则成为一个强连通有向图(该方法对其它结构化程序图同样适用),其
7、圈数为11-7+1=5,与上图的圈复杂度相同: QQ: 28797575计算示例 public String case2(int index, String string) String returnString = null; if (index 0) throw new IndexOutOfBoundsException(exception 0 ); if (index = 1) if (string.length() 2) return string; returnString = returnString1; else if (index = 2) if (string.length(
8、) 2 ); return returnString; QQ: 28797575 根据公式 V(G) = e n + 2 = 12 8 + 2 = 6 。case2的圈复杂段为6。说明一下为什么n = 8,虽然图上的真正节点有12个,但是其中有5个节点为throw、return,这样的节点为end节点,只能记做一个。计算示例检查工具概念概念计算计算检查工具检查工具二二不不二二重构重构 QQ: 28797575检查工具 开发中常用的检测圈复杂度的工具,PMD,checkstyle都可以检测到高复杂度的代码块 Eclipse Metric 插件:有效地查出复杂度 JavaNCSS NCSS表示No
9、n Commenting Source S QQ: 28797575工具工具目的目的Eclipse 插件的插件的 URLCheckStyle编码标准分析http:/eclipse- QQ: 28797575直接管好几百人女:有三室两厅吗?男:没有 女:有路虎,奥迪吗? 男:没有! 女:有7位数存款吗(? 男:没有+! 女:那你有啥? 男:我 女转身就走,。 突然男的说:我管理几百人(。 女立刻回头抱住男的腰,满脸崇拜的说道:死鬼,你不早说,这就够了!那是什么公司高层? 男:我是群主群主烧锅炉翻样中国版主 QQ: 2879757572原则如果你二,你就关注7+2件及以上事情【二货九个圈】如果你不
10、二,你就关注7-2件及以下事情【不二五个圈】圈复杂度高的,可以重构为如:1.参数判断2.取数据3.数据预处理4.数据转换5.返回数据每一步可以是一个独立的方法这样主干逻辑非常的清晰,也就不二金字塔金字塔原理:有目标、有层次、有顺序原理:有目标、有层次、有顺序总分总结构总分总结构把大象放冰箱里,统共分几步?把大象放冰箱里,统共分几步? QQ: 28797575代码大全25知道做什么吗?26总总共共分分5步步评审、会议常见问题27如果去掉第二层如果去掉第二层圈复杂度是。圈复杂度是。 QQ: 28797575写文档没有目录大纲模块设计:一个包下N多个类代码:超大方法超大类圈复杂度的重构控制圈复杂度的
11、N种重构技术-Refactoring: Improving the Design of Existing Code概念概念计算方法计算方法检查工具检查工具二不二二不二重构方法重构方法案例分析案例分析金字塔原理金字塔原理总分总结构总分总结构把大象放冰箱里,统共分几步?把大象放冰箱里,统共分几步?金字塔原理金字塔原理 写代码和写文章、画画写代码和写文章、画画总分总结构总分总结构把大象放冰箱里,统共分几步?把大象放冰箱里,统共分几步?业务重构业务重构架构重构架构重构设计重构设计重构代码重构代码重构重复重复。代码重复、结构重复、逻辑重复。重复的代码是抽象不够的表现。如果是一个独立完整的概念,可以提取成
12、一个子程序(抽象)。举例:多处的排序算法。冗长子程序冗长子程序。如果把子程序的一部分提取来作为另一个独立的子程序,可以让代码更清晰,就提取成子程序。循环过长或嵌套过深循环过长或嵌套过深。循环内部的复杂代码往往可以转换成子程序。嵌套过深可以用前面“语句”中提过的方法解决。子程序命名不当子程序命名不当。需要子程序重命名,或合并、拆分子程序。难懂、拙劣的代码难懂、拙劣的代码。需要重整逻辑和流程。代码重构代码重构降低圈复杂度的方法重构l 概念 重构(Refactoring)就是在不改变软件现有功能的基础上,通过调整程序代码改善软件的质量、性能,使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性
13、。l 重构方法 重复代码或者相似代码提取为一个新的方法 将过长的方法按功能拆分成小的方法 将过大类的功能拆分成多个功能单一的小类l 推荐书籍 重构改善既有代码的设计 作者:Martin Fowler 书中列出了长达70条的重构名录,提供了具体重构的方法和重构的技巧。将帮助开发人员一次一小步地修改代码,减少了开发过程中的风险。 QQ: 28797575Page 32可以直接降低圈复杂度的10种重构技术针对结构化编程:Composing Methods(重新组织你的函数)1.Extract Method(提炼函数)2.Substitute Algorithm(替换你的算法)Simplifying
14、Conditional Expressions(简化条件表达式)3.Decompose Conditional(分解条件式)4.Consolidate Conditional Expression(合并条件式)5.Consolidate Duplicate Conditional Fragments(合并重复的条件片断)6.Remove Control Flag(移除控制标记)Making Method Calls Simpler(简化函数调用)7.Separate Query from Modifier(将查询函数和修改函数分离)8.Parameterize Method(令函数携带参数)9
15、.Replace Parameter with Explicit Methods(以明确函数取代参数)- Refactoring: Improving the Design of Existing Code针对面向对象编程:10.Replace Conditional with Polymorphism(以多态取代条件式)控制圈复杂度的10种重构技术总结可以直接降低圈复杂度的9种重构技术(针对结构化编程):*一、Composing Methods(重新组织你的函数) 1.Extract Method(提炼函数) 分为不同的step步骤进行处理,主干逻辑方法控制在7个以内 将代码放进一个独立函数
16、中,并让函数名称解释该函数的用途 2.Substitute Algorithm(替换你的算法) 将函数本体替换为另一个更清晰、简化的算法 ,如多值匹配 candidates.contains*二、Simplifying Conditional Expressions(简化条件表达式) 3.Decompose Conditional(分解条件式) 从if、then、else三个段落中分别提炼出独立函数 4.Consolidate Conditional Expression(合并条件式) 将多个条件合并 为 c1|c2&c3,并提炼为一个函数 5.Consolidate Duplicate Co
17、nditional Fragments(合并重复的条件片断) 多个条件都执行的代码,将重复代码搬移到条件式之外 6.Remove Control Flag(移除控制标记) 以break和return取代控制标记* 10.Replace Conditional with Polymorphism(以多态取(以多态取代条件式)代条件式) 将整个条件式的每个分支放进一个子类的重载方法将整个条件式的每个分支放进一个子类的重载方法中,然后将原始函数声明为抽象方法中,然后将原始函数声明为抽象方法 面向接口编程,一个接口多种实现;利用state模式减少分支*三三、Making Method Calls Si
18、mpler(简化函数调用)(简化函数调用) 7.Separate Query from Modifier(将查询函数和修改函数分(将查询函数和修改函数分离)离) 单一职责原则,建立两个不同的函数,其中一个负责查建立两个不同的函数,其中一个负责查询,另一个负责修改询,另一个负责修改 8.Parameterize Method(令函数携带参数)(令函数携带参数) 通用函数,建立单一函数,以参数表达那些不同的值建立单一函数,以参数表达那些不同的值 9.Replace Parameter with Explicit Methods(以明确函数取(以明确函数取代参数)代参数) 多个if对应对个函数; 针
19、对该参数的每一个可能值,建立针对该参数的每一个可能值,建立一个独立函数一个独立函数 - Refactoring: Improving the Design of Existing CodePage 34Extract Method(提炼函数)void printOwing(double previousAmount) Enumeration e = _orders.elements(); double outstanding = previousAmount * 1.2; / print banner System.out.println (*); System.out.println (*
20、Customer Owes *); System.out.println (*); / calculate outstanding while (e.hasMoreElements() Order each = (Order) e.nextElement(); outstanding += each.getAmount(); /print details System.out.println (name: + _name); System.out.println (amount + outstanding);void printOwing(double previousAmount) prin
21、tBanner(); double outstanding = getOutstanding(previousAmount * 1.2); printDetails(outstanding);void printBanner() / print banner System.out.println (*); System.out.println (* Customer Owes *);double getOutstanding(double initialValue) double result = initialValue; Enumeration e = _orders.elements()
22、; while (e.hasMoreElements() Order each = (Order) e.nextElement(); result += each.getAmount(); return result;void printDetails (double outstanding) System.out.println (name: + _name); System.out.println (amount + outstanding);将这段代码放进一个独立函数中,将这段代码放进一个独立函数中,并让函数名称解释该函数的用途并让函数名称解释该函数的用途你有一段代码可以被组织在一起并独
23、立出来Page 35Substitute Algorithm(替换你的算法)String foundPerson(String people) for (int i = 0; i people.length; i+) if (peoplei.equals (Don) return Don; if (peoplei.equals (John) return John; if (peoplei.equals (Kent) return Kent; return ;String foundPerson(String people) List candidates = Arrays.asList(ne
24、w StringDon, John,Kent); for (int i=0; ipeople.length; i+) if (candidates.contains(peoplei) return peoplei; return ;你想要把某个算法替换为另一个更清晰的算法将函数本体替换为另一个算法多值判断用集合多个key,用map【当这个值,调用某个服务】多值判断用集合Page 36Decompose Conditional(分解条件式)if (date.before (SUMMER_START) | date.after(SUMMER_END) charge = quantity * _wi
25、nterRate + _winterServiceCharge;else charge = quantity * _summerRate;if (notSummer(date) charge = winterCharge(quantity);else charge = summerCharge (quantity);你有一个复杂的条件语句从从if、then、else三个段落中分别提炼出独立函数三个段落中分别提炼出独立函数专注、聚焦专注、聚焦Page 37Consolidate Conditional Expression(合并条件式)double disabilityAmount() if (
26、_seniority 12) return 0; if (_isPartTime) return 0; / compute the disability amountdouble disabilityAmount() if (isNotEligableForDisability() return 0; / compute the disability amount将这些判断合并为一个条件式,并将这个条件式提炼成为一个独立函数将这些判断合并为一个条件式,并将这个条件式提炼成为一个独立函数你有一系列条件判断,都得到相同结果Page 38Consolidate Duplicate Condition
27、al Fragments(合并重复的条件片断)if (isSpecialDeal() total = price * 0.95; send(); else total = price * 0.98; send(); if (isSpecialDeal() total = price * 0.95;else total = price * 0.98;send();在条件式的每个分支上有着相同的一段代码。将这段重复代码搬移到条件式之外将这段重复代码搬移到条件式之外反反CVS模式模式Page 39Remove Control Flag(移除控制标记)void checkSecurity(String
28、 people) boolean found = false; for (int i = 0; i people.length; i+) if (! found) if (peoplei.equals (Don) sendAlert(); found = true; if (peoplei.equals (John) sendAlert(); found = true; void checkSecurity(String people) for (int i = 0; i 100) result += (Math.min (lastUsage(),200) - 100) * 0.05; ; i
29、f (lastUsage() 200) result += (lastUsage() - 200) * 0.07; ; return new Dollars (result);Dollars baseCharge() double result = usageInRange(0, 100) * 0.03; result += usageInRange (100,200) * 0.05; result += usageInRange (200, Integer.MAX_VALUE) * 0.07; return new Dollars (result);int usageInRange(int
30、start, int end) if (lastUsage() start) return Math.min(lastUsage(),end) -start; else return 0;若干函数做了类似的工作,但在函数本体中却包含了不同的值建立单一函数,以参数表达那些不同的值建立单一函数,以参数表达那些不同的值重构为多参函数重构为多参函数Page 42Replace Parameter with Explicit Methods(以明确函数取代参数)void setValue (String name, int value) if (name.equals(height) _height =
31、 value; if (name.equals(width) _width = value; Assert.shouldNeverReachHere();void setHeight(int arg) _height = arg;void setWidth (int arg) _width = arg;函数实现完全取决于参数值而采取不同反应针对该参数的每一个可能值,建立一个独立函数针对该参数的每一个可能值,建立一个独立函数Page 43Replace Conditional with Polymorphism(以多态取代条件式)double getSpeed() switch (_type)
32、case EUROPEAN: return getBaseSpeed(); case AFRICAN: return getBaseSpeed() - getLoadFactor() *_numberOfCoconuts; case NORWEGIAN_BLUE: return (_isNailed) ? 0 : getBaseSpeed(_voltage); throw new RuntimeException (Should be unreachable);你手上有个条件式,它根据对象类型的不同而选择不同的行为将整个条件式的每个分支放进一个子类的重载方法中,然后将原始函数声明为抽象方法将整
33、个条件式的每个分支放进一个子类的重载方法中,然后将原始函数声明为抽象方法+getSpeed()BirdBird+getSpeed()EuropeanEuropean+getSpeed()AfricanAfrican+getSpeed()Norwegian BlueNorwegian Blue面向接口编程面向接口编程利用state模式减少分支 刘翔有三种状态三种状态,生病状态,正常状态,兴奋状态public void run() if(state = NORMAL_STATE) /正常状态下跑 System.out.println(100米,跑完共用时15秒!); else if(state =
34、 MALUM_STATE) /生病状态下跑 System.out.println(100米,跑完共用时20秒!); else if(state = EXCITED_STATE) /兴奋状态下跑 System.out.println(100米,跑完共用时10秒!); else System.out.println(未知的状态);public interface IState public void doRun(); public class ExcitedState implements IState public void doRun() System.out.println(100米,跑完共
35、用时10钞!); public class MalumState implements IState public void doRun() System.out.println(100米,跑完共用时20秒!); public class NormalState implements IState public void doRun() System.out.println(100米,跑完共用时15秒!); 采用状态模式的运动员public class Gamer /当前状态 private IState state = new NormalState(); /改变状态的方法 public v
36、oid setState(IState state) this.state = state; /状态行为方法,同上面的Gamer 类相比这里没有if.else if判断 public void run() state.doRun(); 利用state模式减少分支 public static void main(String args) /没有使用状态设计模式 com.bill99.pattern.Gamer game = new com.bill99.pattern.Gamer(); game.setState(0); game.run(); game.setState(1); game.ru
37、n(); game.setState(2); game.run(); System.out.println(-); /使用状态设计模式 /正常状态下跑 Gamer gamer = new Gamer(); gamer.run(); /生病状态下跑 gamer.setState(new MalumState(); gamer.run(); /兴奋状态下跑 gamer.setState(new ExcitedState(); gamer.run(); SuperExcitedState假如我们再扩展一个超级兴奋的状态SuperExcitedState,只需实现IState接口,定义好该状态的行为,
38、调用如下gamer.setState(new SuperExcitedState();gamer.run();如果以后维护的话,要再加一个超级兴奋的状态,得要改原来的源代码,添加一个代表超级兴奋的成员变量,再改if.else if判断,这样做不符合OO设计原则,实现不了程序的松耦合。控制圈复杂度的10种重构技术总结可以直接降低圈复杂度的9种重构技术(针对结构化编程):*一、Composing Methods(重新组织你的函数) 1.Extract Method(提炼函数) 分为不同的step步骤进行处理,主干逻辑方法控制在7个以内 将代码放进一个独立函数中,并让函数名称解释该函数的用途 2.S
39、ubstitute Algorithm(替换你的算法) 将函数本体替换为另一个更清晰、简化的算法 ,如多值匹配 candidates.contains*二、Simplifying Conditional Expressions(简化条件表达式) 3.Decompose Conditional(分解条件式) 从if、then、else三个段落中分别提炼出独立函数 4.Consolidate Conditional Expression(合并条件式) 将多个条件合并 为 c1|c2&c3,并提炼为一个函数 5.Consolidate Duplicate Conditional Fragments(
40、合并重复的条件片断) 多个条件都执行的代码,将重复代码搬移到条件式之外 6.Remove Control Flag(移除控制标记) 以break和return取代控制标记* 10.Replace Conditional with Polymorphism(以多态取(以多态取代条件式)代条件式) 将整个条件式的每个分支放进一个子类的重载方法将整个条件式的每个分支放进一个子类的重载方法中,然后将原始函数声明为抽象方法中,然后将原始函数声明为抽象方法 面向接口编程,一个接口多种实现;利用state模式减少分支*三三、Making Method Calls Simpler(简化函数调用)(简化函数调用
41、) 7.Separate Query from Modifier(将查询函数和修改函数分(将查询函数和修改函数分离)离) 单一职责原则,建立两个不同的函数,其中一个负责查建立两个不同的函数,其中一个负责查询,另一个负责修改询,另一个负责修改 8.Parameterize Method(令函数携带参数)(令函数携带参数) 通用函数,建立单一函数,以参数表达那些不同的值建立单一函数,以参数表达那些不同的值 9.Replace Parameter with Explicit Methods(以明确函数取(以明确函数取代参数)代参数) 多个if对应对个函数; 针对该参数的每一个可能值,建立针对该参数的
42、每一个可能值,建立一个独立函数一个独立函数 - Refactoring: Improving the Design of Existing Code重构案例控制圈复杂度的N种重构技术-Refactoring: Improving the Design of Existing Code概念概念计算方法计算方法检查工具检查工具二不二二不二重构方法重构方法案例分析案例分析代码生成工具优化重构前重构后1.生成参数信息生成参数信息2.生成文件内容生成文件内容3.写到文件写到文件4.打印日志打印日志混乱的代码是混乱思维的产物上传文件代码示例1.不是不是excel,返回,返回2.超过大小限制,返回超过大小限
43、制,返回3.不满足条件,返回不满足条件,返回4.文件内容校验文件内容校验5.多处String类型非空判断if (StringUtil.isEmpty(username) throw new ICRClientException(username can not be null);if (StringUtil.isEmpty(password) throw new ICRClientException(password can not be null);if (udto = null) throw new ICRClientException(ICRUploadDTO can not be nu
44、ll);/将原来的地方替换为checkStringParamEmpty(username, username);checkStringParamEmpty(password, password);checkStringParamEmpty(udto.getUrlPath(), urlPath);./新增一个方法private void checkStringParamEmpty(String value, String name) throws ICRClientException if (StringUtil.isEmpty(value) throw new ICRClientExcepti
45、on(name + can not be null); 多String值判断if (!udto.getPriority().equals(0) & !udto.getPriority().equals(1) & !udto.getPriority().equals(2) & !udto.getPriority().equals(3)throw new ICRClientException(priority must be 0/1/2/3);/将原来代码替换为checkValueWithinList(udto.getPriority();./新增一个方法:private void checkVa
46、lueWithinList(String priority) throws ICRClientException if (!Arrays.asList(0, 1, 2, 3).contains(priority) throw new ICRClientException(priority must be 0/1/2/3); 多个catch的内容相同int code = 0;try code = httpClient.executeMethod(post); catch (HttpException e) throw new ICRClientException(e.getMessage(),
47、e); catch (IOException e) throw new ICRClientException(e.getMessage(), e);/将原来的地方替换为int code = executeHttpClient(httpClient, post);./新增一个方法private int executeHttpClient(HttpClient httpClient, PostMethod post) throws ICRClientException int code; try code = httpClient.executeMethod(post); catch (Excep
48、tion e) throw new ICRClientException(e.getMessage(), e); return code;if判断结果复杂化 if (code = 200) try if (post.getResponseBodyAsString().equals(ok) return true; catch (IOException e) throw new ICRClientException(e.getMessage(), e); return false; else if (code = 500) throw new ICRClientException(post.ge
49、tResponseBodyAsString(); else throw new ICRClientException(code + : + post.getStatusText();return returnFinialResult(post, code);./新增一个方法private boolean returnFinialResult(PostMethod post, int code) throws ICRClientException, IOException if (code = 500) throw new ICRClientException(post.getResponseB
50、odyAsString(); if (code != 200) throw new ICRClientException(code + : + post.getStatusText(); try return post.getResponseBodyAsString().equals(ok); catch (IOException e) throw new ICRClientException(e.getMessage(), e); 本地变量始终不为nullpublic boolean uploadToICR(String username, String password, ICRUploa
51、dDTO udto) throws ICRClientException HttpClient httpClient = null; PostMethod post = null; httpClient = new HttpClient(); /some code here finally if (post != null) post.releaseConnection(); if (httpClient != null) httpClient.getHttpConnectionManager().closeIdleConnections(0); public boolean uploadTo
52、ICR(String username, String password, ICRUploadDTO udto) throws ICRClientException HttpClient httpClient = new HttpClient(); PostMethod post = null; /some code here finally if (post != null) post.releaseConnection(); 读取IO流的方法,为什么要自己实现?private byte readData(InputStream ins) throws IOException byte bu
53、f = new byte2048; int count = 0; int len = 0; byte data = new byte2048; byte result = null; try while (len = ins.read(data, 0, 2048) != -1) int newcount = count + len; if (newcount buf.length) byte newbuf = new byteMath .max(buf.length 1, newcount); System.arraycopy(buf, 0, newbuf, 0, count); buf =
54、newbuf; System.arraycopy(data, 0, buf, count, len); count = newcount; result = new bytecount; System.arraycopy(buf, 0, result, 0, count); finally ins.close(); return result;/使用apache io API的实现: byte bytes = IOUtils.toByteArray(inputStream); /使用guava API的实现: byte bytes1 = ByteStreams.toByteArray(inputStream);持续重构重构要尽早且要经常进行太多导入表明一个类过多地依赖于其他的类。您会注意到,由于一个类与很多其他的类耦合得太紧密,修改这个类会导致必须对很多其他的类进行修改
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五年度艺术市场推广正规艺术家合作协议
- 2025年度火锅店合伙人合作协议书:特色火锅底料配方保密协议
- 软件项目开发与测试进度表
- 机械制造工艺与设备操作指南
- 跨部门团队协作策略研讨会纪要报告
- 贵州国企招聘2024贵州页岩气勘探开发有限责任公司招聘42人笔试参考题库附带答案详解
- 农业文化传承与推广指南
- 四川宽窄优品商贸有限责任公司成都分公司招聘笔试参考题库附带答案详解
- 贵州2025年贵州开放大学(贵州职业技术学院)招聘41人笔试历年参考题库附带答案详解
- 潍坊2025年山东潍坊市坊子区事业单位招聘35人笔试历年参考题库附带答案详解
- 2025年重庆市安全员《B证》考试题库及答案
- 《脑出血》课件完整版
- 《锂离子电池用二氟草酸硼酸锂》
- 全国第三届职业技能大赛(数字孪生应用技术)选拔赛理论考试题及答案
- 小学一年级上册数学课件专题一 数与代数
- 2024-2030年中国软水机行业竞争力策略及发展潜力分析报告版
- 议论文及其结构+课件统编版高中语文必修上册
- 2024年列车员技能竞赛理论考试题库500题(含答案)
- 同行战略合作协议书范本
- 中南大学《通信原理》2023-2024学年第一学期期末试卷
- ECharts数据可视化课件 第2章 折线图和饼图
评论
0/150
提交评论