好.圈复杂度概念.重构方法及案例.潘洪亮2015-12-03_第1页
好.圈复杂度概念.重构方法及案例.潘洪亮2015-12-03_第2页
好.圈复杂度概念.重构方法及案例.潘洪亮2015-12-03_第3页
好.圈复杂度概念.重构方法及案例.潘洪亮2015-12-03_第4页
好.圈复杂度概念.重构方法及案例.潘洪亮2015-12-03_第5页
已阅读5页,还剩58页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

扬帆起航圈复杂度CyclomaticComplexityis17(maxallowedis7).CyclomaticComplexityisX(maxallowedisX)hongliangpan@

我的QQ:28797575知道做什么吗?文档示例无目录有目录不聚焦不知道目标,不知道总体结构不知道是否合理没有层次是否有遗漏带来时间成本质量问题4知道做什么吗?圈复杂度概念概念计算方法检查工具二不二重构方法案例分析McCabe复杂度圈复杂度基本复杂度模块设计复杂度设计复杂度集成复杂度行数全局数据复杂度局部数据复杂度病态数据复杂度规范化复杂度框架群:181124238我的QQ:307087558(1)圈复杂度(CyclomaticComplexity(v(G)))概念圈复杂度是用来衡量一个模块判定结构的复杂程度,数量上表现为独立路径的条数。计算方法如果一个模块流程图有e条边n个节点,它的圈复杂度v(G)=e-n+2。

圈复杂度(CyclomaticComplexity)是一种代码复杂度的衡量标准。它可以用来衡量一个模块判定结构的复杂程度,数量上表现为独立线性路径条数,也可理解为覆盖所有的可能情况最少使用的测试用例数。圈复杂度大说明程序代码的判断逻辑复杂,可能质量低且难于测试和维护。程序的可能错误和高的圈复杂度有着很大关系。

圈复杂度主要与分支语句(if、else、switch、for等)的个数成正相关。当一段代码中含有较多的分支语句,其逻辑复杂程度就会增加。什么是圈复杂度示例下面这个实例中,单元测试的覆盖率可以达到100%,但是很容易发现这其中已经漏掉了一个NPE的测试用例。case1方法的圈复杂度为2,因此至少需要2个用例才能完全覆盖到其所有的可能情况。//程序原代码,圈复杂度为2

publicStringcase1(intnum){

Stringstring=null;

if(num==1){

string="String";

}

returnstring.substring(0);

}//上面代码的单元测试代码

publicvoidtestCase1(){

Stringtest1=case1(1);

}

圈复杂度主要与分支语句(if、else、,switch等)的个数成正相关。当一段代码中含有较多的分支语句,其逻辑复杂程度就会增加。圈复杂度计算概念计算方法检查工具二不二重构方法案例分析示例如果一个模块流程如下有e条边n个节点,它的圈复杂度v(G)=e-n+2例:

圈复杂度的计算

圈复杂度(cyclomaticcomplexity):M=E−N+2P

E:边的数量

N:节点的数量

P:分离部分的数量,一般为1,都是联通的

圈数(cyclomaticnumber):M=E−N+P

E,N,P参数同上

圈复杂度和圈数之间的关系为:

对有向图A,将A的每个出口(exit)与相应的入口(entrance)相连得到有向图B,则A的圈复杂度与B的圈数相等

圈复杂度又叫做CC复杂度,也可能被称为循环复杂度,它表达的是if..then..else..,swith..case..,循环语句等分支语句造成的程序控制流复杂程度

计算公式补充通常使用的计算公式是V(G)=e–n+2,e

代表在控制流图中的边的数量(对应代码中顺序结构的部分),n

代表在控制流图中的节点数量,包括起点和终点(1、所有终点只计算一次,即便有多个return或者throw;2、节点对应代码中的分支语句)。例如下图示例一个单入口、单出口的程序图(不是结构化程序图),其圈复杂度为10-7+2=5:从节点G到A添加一条有向边,则成为一个强连通有向图(该方法对其它结构化程序图同样适用),其圈数为11-7+1=5,与上图的圈复杂度相同:计算示例

public

Stringcase2(int

index,Stringstring){

StringreturnString=

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()<5){

return

string;

}

returnString=

"returnString2";

}

else

{

throw

new

IndexOutOfBoundsException("exception>2");

}

return

returnString;

}根据公式

V(G)=e–n+2=12–8+2=6

。case2的圈复杂段为6。说明一下为什么n=8,虽然图上的真正节点有12个,但是其中有5个节点为throw、return,这样的节点为end节点,只能记做一个。计算示例检查工具概念计算检查工具二不二重构检查工具开发中常用的检测圈复杂度的工具,PMD,checkstyle都可以检测到高复杂度的代码块SourceMonitorEclipseMetric插件:有效地查出复杂度JavaNCSSNCSS表示NonCommentingSourceStatements工具目的Eclipse插件的URLCheckStyle编码标准分析/update/Coverlipse测试代码覆盖率/updateCPD复制/粘贴检验/eclipse/JDepend包依赖项分析http://andrei.gmxhome.de/eclipse/Metrics复杂度监控/update7±2原则概念计算方法检查工具二不二重构方法案例分析直接管好几百人女:有三室两厅吗?男:没有女:有路虎,奥迪吗?男:没有!女:有7位数存款吗(?男:没有+!女:那你有啥?男:我………女转身就走,。突然男的说:我管理几百人(。。。女立刻回头抱住男的腰,满脸崇拜的说道:死鬼,你不早说,这就够了!!!那是什么公司高层?男:我是群主群主烧锅炉翻样中国版主7±2原则如果你二,你就关注7+2件及以上事情【二货九个圈】如果你不二,你就关注7-2件及以下事情【不二五个圈】圈复杂度高的,可以重构为如:1.参数判断2.取数据3.数据预处理4.数据转换5.返回数据

每一步可以是一个独立的方法这样主干逻辑非常的清晰,也就不二金字塔原理:有目标、有层次、有顺序总分总结构把大象放冰箱里,统共分几步?代码大全25知道做什么吗?26总共分5步评审、会议常见问题27如果去掉第二层圈复杂度是。。写文档没有目录大纲模块设计:一个包下N多个类代码:超大方法超大类圈复杂度的重构控制圈复杂度的N种重构技术Refactoring:ImprovingtheDesignofExistingCode概念计算方法检查工具二不二重构方法案例分析金字塔原理总分总结构把大象放冰箱里,统共分几步?金字塔原理写代码和写文章、画画总分总结构把大象放冰箱里,统共分几步?业务重构架构重构设计重构代码重构重复。代码重复、结构重复、逻辑重复。重复的代码是抽象不够的表现。如果是一个独立完整的概念,可以提取成一个子程序(抽象)。举例:多处的排序算法。冗长子程序。如果把子程序的一部分提取来作为另一个独立的子程序,可以让代码更清晰,就提取成子程序。循环过长或嵌套过深。循环内部的复杂代码往往可以转换成子程序。嵌套过深可以用前面“语句”中提过的方法解决。子程序命名不当。需要子程序重命名,或合并、拆分子程序。难懂、拙劣的代码。需要重整逻辑和流程。…代码重构重构、金字塔原理降低圈复杂度的方法——重构概念重构(Refactoring)就是在不改变软件现有功能的基础上,通过调整程序代码改善软件的质量、性能,使其程序的设计模式和架构更趋合理,提高软件的扩展性和维护性。重构方法重复代码或者相似代码提取为一个新的方法将过长的方法按功能拆分成小的方法将过大类的功能拆分成多个功能单一的小类推荐书籍《重构——改善既有代码的设计》作者:MartinFowler书中列出了长达70条的重构名录,提供了具体重构的方法和重构的技巧。将帮助开发人员一次一小步地修改代码,减少了开发过程中的风险。Page32可以直接降低圈复杂度的10种重构技术针对结构化编程:ComposingMethods(重新组织你的函数) 1.ExtractMethod(提炼函数) 2.SubstituteAlgorithm(替换你的算法)SimplifyingConditionalExpressions(简化条件表达式) 3.DecomposeConditional(分解条件式)

4.ConsolidateConditionalExpression(合并条件式)

5.ConsolidateDuplicateConditionalFragments(合并重复的条件片断) 6.RemoveControlFlag(移除控制标记)MakingMethodCallsSimpler(简化函数调用) 7.SeparateQueryfromModifier(将查询函数和修改函数分离) 8.ParameterizeMethod(令函数携带参数) 9.ReplaceParameterwithExplicitMethods(以明确函数取代参数)

Refactoring:ImprovingtheDesignofExistingCode针对面向对象编程:

10.ReplaceConditionalwithPolymorphism(以多态取代条件式)控制圈复杂度的10种重构技术总结可以直接降低圈复杂度的9种重构技术(针对结构化编程):*一、ComposingMethods(重新组织你的函数)

1.Extract

Method(提炼函数)

分为不同的step步骤进行处理,主干逻辑方法控制在7个以内

将代码放进一个独立函数中,并让函数名称解释该函数的用途

2.Substitute

Algorithm(替换你的算法)将函数本体替换为另一个更清晰、简化的算法,如多值匹配candidates.contains*二、SimplifyingConditionalExpressions(简化条件表达式)

3.Decompose

Conditional(分解条件式)

从if、then、else三个段落中分别提炼出独立函数

4.Consolidate

ConditionalExpression(合并条件式)

将多个条件合并为c1||c2&&c3,并提炼为一个函数

5.Consolidate

DuplicateConditionalFragments(合并重复的条件片断)

多个条件都执行的代码,将重复代码搬移到条件式之外

6.Remove

ControlFlag(移除控制标记)

以break和return取代控制标记

*四、针对面向对象编程:

10.Replace

ConditionalwithPolymorphism(以多态取代条件式)

将整个条件式的每个分支放进一个子类的重载方法中,然后将原始函数声明为抽象方法

面向接口编程,一个接口多种实现;利用state模式减少分支*三、MakingMethodCallsSimpler(简化函数调用)

7.Separate

QueryfromModifier(将查询函数和修改函数分离)

单一职责原则,建立两个不同的函数,其中一个负责查询,另一个负责修改

8.Parameterize

Method(令函数携带参数)

通用函数,建立单一函数,以参数表达那些不同的值

9.Replace

ParameterwithExplicitMethods(以明确函数取代参数)

多个if对应对个函数;

针对该参数的每一个可能值,建立一个独立函数

Refactoring:ImprovingtheDesignofExistingCodePage34ExtractMethod(提炼函数)voidprintOwing(doublepreviousAmount){Enumeratione=_orders.elements();doubleoutstanding=previousAmount*1.2;

//printbannerSystem.out.println("**************************");System.out.println("*****CustomerOwes******");System.out.println("**************************");//calculateoutstandingwhile(e.hasMoreElements()){Ordereach=(Order)e.nextElement();outstanding+=each.getAmount();}//printdetailsSystem.out.println("name:"+_name);System.out.println("amount"+outstanding);}voidprintOwing(doublepreviousAmount){printBanner();doubleoutstanding=getOutstanding(previousAmount*1.2);printDetails(outstanding);}voidprintBanner(){//printbannerSystem.out.println("**************************");System.out.println("*****CustomerOwes******");}doublegetOutstanding(doubleinitialValue){doubleresult=initialValue;Enumeratione=_orders.elements();while(e.hasMoreElements()){Ordereach=(Order)e.nextElement();result+=each.getAmount();}returnresult;}voidprintDetails(doubleoutstanding){System.out.println("name:"+_name);System.out.println("amount"+outstanding);}将这段代码放进一个独立函数中,并让函数名称解释该函数的用途你有一段代码可以被组织在一起并独立出来Page35SubstituteAlgorithm(替换你的算法)StringfoundPerson(String[]people){for(inti=0;i<people.length;i++){if(people[i].equals("Don"))return"Don";if(people[i].equals("John"))return"John";if(people[i].equals("Kent"))return"Kent";}return"";}StringfoundPerson(String[]people){Listcandidates=Arrays.asList(newString[]{"Don","John","Kent"});for(inti=0;i<people.length;i++)if(candidates.contains(people[i]))returnpeople[i];return"";}你想要把某个算法替换为另一个更清晰的算法将函数本体替换为另一个算法多值判断用集合多个key,用map【当这个值,调用某个服务】多值判断用集合Page36DecomposeConditional(分解条件式)if(date.before(SUMMER_START)||date.after(SUMMER_END))charge=quantity*_winterRate+_winterServiceCharge;elsecharge=quantity*_summerRate;if(notSummer(date))charge=winterCharge(quantity);elsecharge=summerCharge(quantity);你有一个复杂的条件语句从if、then、else三个段落中分别提炼出独立函数专注、聚焦Page37ConsolidateConditionalExpression(合并条件式)doubledisabilityAmount(){if(_seniority<2)return0;if(_monthsDisabled>12)return0;if(_isPartTime)return0;//computethedisabilityamountdoubledisabilityAmount(){if(isNotEligableForDisability())return0;//computethedisabilityamount将这些判断合并为一个条件式,并将这个条件式提炼成为一个独立函数你有一系列条件判断,都得到相同结果Page38ConsolidateDuplicateConditionalFragments(合并重复的条件片断)if(isSpecialDeal()){total=price*0.95;send();}else{total=price*0.98;send();}if(isSpecialDeal())total=price*0.95;elsetotal=price*0.98;send();在条件式的每个分支上有着相同的一段代码。将这段重复代码搬移到条件式之外反CVS模式Page39RemoveControlFlag(移除控制标记)voidcheckSecurity(String[]people){booleanfound=false;for(inti=0;i<people.length;i++){if(!found){if(people[i].equals("Don")){sendAlert();found=true;}if(people[i].equals("John")){sendAlert();found=true;}}}}voidcheckSecurity(String[]people){for(inti=0;i<people.length;i++){if(people[i].equals("Don")){sendAlert();break;}if(people[i].equals("John")){sendAlert();break;}}}在一系列布尔表达式种,某个变量带有【控制标记】的作用以break和return取代控制标记Page40SeparateQueryfromModifier(将查询函数和修改函数分离)某个函数既返回对象状态值,又修改对象状态建立两个不同的函数,其中一个负责查询,另一个负责修改CustomergetTotalOutstandingAndSetReadyForSummariesCustomergetTotalOutstandingSetReadyForSummaries反一心二用、左右互搏Page41ParameterizeMethod(令函数携带参数)DollarsbaseCharge(){doubleresult=Math.min(lastUsage(),100)*0.03;if(lastUsage()>100){result+=(Math.min(lastUsage(),200)-100)*0.05;};if(lastUsage()>200){result+=(lastUsage()-200)*0.07;};returnnewDollars(result);}DollarsbaseCharge(){doubleresult=usageInRange(0,100)*0.03;result+=usageInRange(100,200)*0.05;result+=usageInRange(200,Integer.MAX_VALUE)*0.07;returnnewDollars(result);}intusageInRange(intstart,intend){if(lastUsage()>start)returnMath.min(lastUsage(),end)-start;elsereturn0;}若干函数做了类似的工作,但在函数本体中却包含了不同的值建立单一函数,以参数表达那些不同的值重构为多参函数Page42ReplaceParameterwithExplicitMethods(以明确函数取代参数)

voidsetValue(Stringname,intvalue){if(name.equals("height"))_height=value;if(name.equals("width"))_width=value;Assert.shouldNeverReachHere();}voidsetHeight(intarg){_height=arg;}voidsetWidth(intarg){_width=arg;}函数实现完全取决于参数值而采取不同反应针对该参数的每一个可能值,建立一个独立函数Page43ReplaceConditionalwithPolymorphism(以多态取代条件式)

doublegetSpeed(){switch(_type){caseEUROPEAN:returngetBaseSpeed();caseAFRICAN:returngetBaseSpeed()-getLoadFactor()*_numberOfCoconuts;caseNORWEGIAN_BLUE:return(_isNailed)?0:getBaseSpeed(_voltage);}thrownewRuntimeException("Shouldbeunreachable");}你手上有个条件式,它根据对象类型的不同而选择不同的行为将整个条件式的每个分支放进一个子类的重载方法中,然后将原始函数声明为抽象方法面向接口编程利用state模式减少分支

刘翔有三种状态三种状态,生病状态,正常状态,兴奋状态publicvoidrun(){if(state==NORMAL_STATE){//正常状态下跑

System.out.println("100米,跑完共用时15秒!");}

elseif(state==MALUM_STATE){//生病状态下跑System.out.println("100米,跑完共用时20秒!");

}

elseif(state==EXCITED_STATE){//兴奋状态下跑

System.out.println("100米,跑完共用时10秒!");}else{System.out.println("未知的状态");}}publicinterfaceIState{publicvoiddoRun();}publicclassExcitedStateimplementsIState{publicvoiddoRun(){

System.out.println("100米,跑完共用时10钞!");}}publicclassMalumStateimplementsIState{

publicvoiddoRun(){System.out.println("100米,跑完共用时20秒!");}}publicclassNormalStateimplementsIState{

publicvoiddoRun(){System.out.println("100米,跑完共用时15秒!");}}采用状态模式的运动员publicclassGamer{//当前状态

privateIStatestate=newNormalState();//改变状态的方法

publicvoidsetState(IStatestate){this.state=state;}//状态行为方法,同上面的Gamer类相比这里没有if..elseif判断

publicvoidrun(){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.run();

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接口,定义好该状态的行为,调用如下gamer.setState(new

SuperExcitedState());gamer.run();如果以后维护的话,要再加一个超级兴奋的状态,得要改原来的源代码,添加一个代表超级兴奋的成员变量,再改if..elseif判断,这样做不符合OO设计原则,实现不了程序的松耦合。控制圈复杂度的10种重构技术总结可以直接降低圈复杂度的9种重构技术(针对结构化编程):*一、ComposingMethods(重新组织你的函数)

1.Extract

Method(提炼函数)

分为不同的step步骤进行处理,主干逻辑方法控制在7个以内

将代码放进一个独立函数中,并让函数名称解释该函数的用途

2.Substitute

Algorithm(替换你的算法)将函数本体替换为另一个更清晰、简化的算法,如多值匹配candidates.contains*二、SimplifyingConditionalExpressions(简化条件表达式)

3.Decompose

Conditional(分解条件式)

从if、then、else三个段落中分别提炼出独立函数

4.Consolidate

ConditionalExpression(合并条件式)

将多个条件合并为c1||c2&&c3,并提炼为一个函数

5.Consolidate

DuplicateConditionalFragments(合并重复的条件片断)

多个条件都执行的代码,将重复代码搬移到条件式之外

6.Remove

ControlFlag(移除控制标记)

以break和return取代控制标记

*四、针对面向对象编程:

10.Replace

ConditionalwithPolymorphism(以多态取代条件式)

将整个条件式的每个分支放进一个子类的重载方法中,然后将原始函数声明为抽象方法

面向接口编程,一个接口多种实现;利用state模式减少分支*三、MakingMethodCallsSimpler(简化函数调用)

7.Separate

QueryfromModifier(将查询函数和修改函数分离)

单一职责原则,建立两个不同的函数,其中一个负责查询,另一个负责修改

8.Parameterize

Method(令函数携带参数)

通用函数,建立单一函数,以参数表达那些不同的值

9.Replace

ParameterwithExplicitMethods(以明确函数取代参数)

多个if对应对个函数;

针对该参数的每一个可能值,建立一个独立函数

Refactoring:ImprovingtheDesignofExistingCode重构案例控制圈复杂度的N种重构技术Refactoring:ImprovingtheDesignofExistingCode概念计算方法检查工具二不二重构方法案例分析代码生成工具优化重构前重构后1.生成参数信息2.生成文件内容3.写到文件4.打印日志混乱的代码是混乱思维的产物上传文件代码示例1.不是excel,返回2.超过大小限制,返回3.不满足条件,返回4.文件内容校验5.多处String类型非空判断if(StringUtil.isEmpty(username))thrownewICRClientException("usernamecannotbenull");if(StringUtil.isEmpty(password))thrownewICRClientException("passwordcannotbenull");if(udto==null)thrownewICRClientException("ICRUploadDTOcannotbenull");//将原来的地方替换为checkStringParamEmpty(username,"username");checkStringParamEmpty(password,"password");checkStringParamEmpty(udto.getUrlPath(),"urlPath");...//新增一个方法privatevoidcheckStringParamEmpty(Stringvalue,Stringname)throwsICRClientException{if(StringUtil.isEmpty(value)){thrownewICRClientException(name+"cannotbenull");}}多String值判断if(!udto.getPriority().equals("0")&&!udto.getPriority().equals("1")&&!udto.getPriority().equals("2")&&!udto.getPriority().equals("3"))thrownewICRClientException("prioritymustbe0/1/2/3");//将原来代码替换为checkValueWithinList(udto.getPriority());...//新增一个方法:privatevoidcheckValueWithinList(Stringpriority)throwsICRClientException{if(!Arrays.asList("0","1","2","3").contains(priority)){thrownewICRClientException("prioritymustbe0/1/2/3");}}多个catch的内容相同intcode=0;try{code=httpClient.executeMethod(post);}catch(HttpExceptione){thrownewICRClientException(e.getMessage(),e);}catch(IOExceptione){thrownewICRClientException(e.getMessage(),e);}//将原来的地方替换为intcode=executeHttpClient(httpClient,post);...//新增一个方法privateintexecuteHttpClient(HttpClienthttpClient,PostMethodpost)throwsICRClientException{intcode;try{code=httpClient.executeMethod(post);}catch(Exceptione){thrownewICRClientException(e.getMessage(),e);}returncode;}if判断结果复杂化if(code==200){try{if(post.getResponseBodyAsString().equals("ok")){returntrue;}}catch(IOExceptione){thrownewICRClientException(e.getMessage(),e);}returnfalse;}elseif(code==500){thrownewICRClientException(post.getResponseBodyAsString());}else{thrownewICRClientException(code+":"+post.getStatusText());}returnreturnFinialResult(post,code);...//新增一个方法privatebooleanreturnFinialResult(PostMethodpost,intcode)throwsICRClientException,IOException{if(code==500)thrownewICRClientException(post.getResponseBodyAsString());if(code!=200)thrownewICRClientException(code+":"+post.getStatusText());try{returnpost.getResponseBodyAsString().equals("ok");}catch(IOExceptione){thrownewICRClientException(e.getMessage(),e);}}本地变量始终不为nullpublicbooleanuploadToICR(Stringusername,Stringpassword,ICRUploadDTOudto)throwsICRClientException{HttpClienthttpClient=null;PostMethodpost=null;httpClient=newHttpClient();//somecodehere…}finally{if(post!=null){post.releaseConnection();}if(httpClient!=null){httpClient.getHttpConnectionManager().closeIdleConnections(0);}}publicbooleanuploadToICR(Stringusername,Stringpassword,ICRUploadDTOudto)throwsICRClientException{HttpClienthttpClient=newHttpClient();PostMethodpost=null;//somecodehere…}finally{if(post!=null){post.releaseConnection();}}}读取IO流的方法,为什么要自己实现?privatebyte[]readData(InputStreamins)throwsIOException{byte[]buf=newbyte[2048];intcount=0;intlen=0;bytedata[]=newbyte[2048];byte[]result=null;try{while((len=ins.read(data,0,2048))!=-1){intnewcount=count+len;if(newcount>buf.length){bytenewbuf[]=newbyte[Math.max(buf.length<<1,newcount)];System.arraycopy(buf,0,newbuf,0,count);buf=newbuf;}System.arraycopy(data,0,buf,count,len);count=newcount;}result=newbyte[count];System.arraycopy(buf,0,result,0,count);}finally{ins.close();}re

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论