3901110721李奇软件配置管理实验报告3Word下载.docx
《3901110721李奇软件配置管理实验报告3Word下载.docx》由会员分享,可在线阅读,更多相关《3901110721李奇软件配置管理实验报告3Word下载.docx(38页珍藏版)》请在冰豆网上搜索。
专业4:
一、实验目的
1.熟悉常用的代码味道的涵义和特征;
2.熟悉常用的代码重构手段;
3.学会使用常用重构手段对常见代码味道进行重构;
4.掌握一种代码味道识别工具(CSDT);
5.熟悉Eclipse重构菜单;
6.学会使用EclipseAST来解析Java源代码;
7.设计并实现两种代码味道的自动识别方法;
8.设计并实现一种代码味道的自动重构方法。
二、实验内容
1.根据常见代码味道的特点,选取合适的重构手段对它们进行重构,填写相应的表格;
2.掌握一款代码味道识别工具,并使用该工具对至少一个实验项目进行代码味道识别,寻找存在代码味道的类和代码片段;
【参考资料:
七款代码味道识别工具
3.学习使用Eclipse重构(Refactor)菜单,从实验项目中选取合适的代码进行重构操作;
4.自学EclipseAST,包括获取、访问、创建和修改AST等操作;
【EclipseAST学习资料:
】
5.选取两种代码味道,设计并实现相应的代码味道识别方法,选取至少一个实验项目进行测试;
6.结合EclipseAST,选取一种代码味道,设计并实现一种代码味道的自动重构方法,至少提供两个重构测试用例,并对重构前后的代码进行分析。
补充:
实验素材及相关资料
(1)EclipseAST所需jar包下载地址:
(2)ASTView下载地址:
(3)5个实验项目下载地址:
(4)10个补充实验项目下载地址:
三、实验要求
1.针对常用的代码味道,选择合适的重构手段,填写相应的表格,要求表格需填写完整;
2.选取一款代码味道识别工具,记录对实验项目的代码味道识别结果,包括识别到的类名和代码片段;
3.使用Eclipse重构(Refactor)菜单对实验项目中的代码进行重构(自行选取合适的代码),要求提供重构前后的代码【至少需使用10种重构手段】;
4.针对两种代码味道,设计并实现相应的识别方法,要求对方法原理进行说明,需提供文字介绍(可包含流程图)、核心代码以及相应的测试结果和分析;
5.针对一种代码味道,设计并实现相应的重构方法,要求对重构流程进行说明,需提供文字介绍(可包含流程图)、核心代码以及相应的测试结果和分析。
四、实验步骤
1.填写代码味道和重构手段表格;
2.选取一种代码味道识别工具,对常见代码味道进行识别,记录识别结果;
3.学习使用EclipseRefactor菜单,熟悉至少10种常用的重构操作;
4.学习EclipseAST,熟悉使用AST来解析Java源代码;
5.设计并实现两种代码味道识别方法,对已有项目进行测试,记录与分析实验结果;
6.设计并实现一种代码味道重构方法,对测试用例进行实验,记录与分析实验结果。
五、实验结果
1.针对常用的代码味道,选择合适的重构手段,填写如下表格:
代码味道名称
常用重构手段
过长方法(LongMethod)
抽取函数(ExtractMethod)
以查询取代临时变量(ReplaceTempWithQuery)
引入参数对象(IntroduceParameterObject)
分解条件表达式(DecomposeConditional)
过大类(LargeClass)
太多实例变量或太多代码:
ExtractClass(提炼类)、ExtractSubclass(提炼子类)
把数据和行为移到一个独立的领域对象,但需要保留一些重复数据:
DuplicateObservedData(复制“被监视数据”)
确定客户端如何使用:
ExtractInterface(提炼接口)
基本类型偏执(PrimitiveObsession)
将原本单独存在的数据值替换成对象:
ReplaceDataValuewithObject(以对象取代数据值)
如果想要替换的数据值是类型码,而它并不影响行为:
ReplaceTypeCodewithClass(以类取代类型码)
如果有与类型码相关的条件表达式:
ReplaceTypeCodewithSubclass(以子类取代类型码)、ReplaceTypeCodewithState/Strategy(以State/Strategy取代类型码)
如果有一组应该总是被放在一起的字段:
ExtractClass(提炼函数)
如果在参数列中看到基本类型的数据:
IntroduceParameterObject(引入参数对象)
发现自己正从数组中挑选数据:
ReplaceArraywithObject(以对象取代数组)
纯稚的数据类(DataClass)
对于public字段:
EncapsulateField(封装字段)
如果一个类内含容器类的字段,如果没有得到恰当的封装:
EncapsulateCollection(封装集合)
对于那些不该被其他类修改的字段:
RemoveSettingMethod(移除设值函数)
找出Getter/Setter函数被其他类运用的地点:
MoveMethod(搬移函数)
如果无法搬移整个函数:
ExtractMethod(提炼函数)
将Getter/Setter函数隐藏起来:
HideMethod(隐藏函数)
重复代码(DuplicatedCode)
同一个类的一个/两个方法含有相同的代码:
ExtractMethod(提炼函数)
两个互为兄弟的子类含有相同的代码:
ExtractMethod(提炼函数)、PullUpMethod(函数上移)、FormTemplateMethod(塑造模板函数)
两个毫不相关的类含有相同的代码:
ExtractClass(提炼类)
异曲同工的类(AlternativeClasseswithDifferentInterfaces)
两个函数做同一件事,却有着不同的签名:
RenameMethod(函数改名)
将某些行为移入类,直到两者的协议一致为止:
必须重复而冗赘地移入代码:
ExtractSuperclass(提炼超类)
Switch惊悚现身(SwitchStatement)
与类型码相关的函数或类:
ExtractMethod(提炼函数)、MoveMethod(搬移函数)、ReplaceConditionalwithPolymorphism(以多态取代条件表达式)、ReplaceTypeCodewithSubclass(以子类取代类型码)、ReplaceTypeCodewithState/Strategy(以State/Strategy取代类型码)
只在单一函数中有一些选择事件,且不想改动它们:
ReplaceParameterwithExplicitMethods(以明确函数取代参数)
选择条件之一是null:
IntroduceNullObject(引入Null对象)
令人迷惑的暂时字段(TemporaryField)
一个对象中某个实例变量仅为某种特定情况而定:
在“变量不合法”的情况下创建一个Null对象,从而避免写出条件式代码:
被拒绝的遗赠(RefusedBequest)
子类不想或不需要继承超类(先为子类新建一个兄弟类):
ExtractSubclass(提炼子类)、PushDownMethod(函数下移)、PushDownField(字段下移)
子类复用了超类的行为(实现),却又不愿意支持超类的接口,拒绝继承超类的实现:
ReplaceInheritancewithDelegation(以委托取代继承)
数据泥团(DataClumps)
两个类中有相同的字段、许多函数签名中的参数相同:
缩短参数列表、简化函数调用:
IntroduceParameterObject(引入参数对象)、PreserveWholeObject(保持对象完整)
狎昵关系(InappropriateIntimacy)
类之间的关系过于亲密:
MoveMethod(搬移函数)、MoveField(搬移字段)、ChangeBidirectionalAssociationtoUnidirectional(将双向关联改为单向关联)
如果两个类存在共同点:
ExtractClass(提炼类)、HideDelegate(隐藏“委托关系”)
从继承体系中分离子类:
冗赘类(LazyClass)
对于几乎没用的组件:
InlineClass(将类内联化)
如果某些子类没有做足够的工作:
CollapseHierarchy(折叠继承体系)
依恋情结(FeatureEnvy)
函数对某个类的兴趣高过对自己所处类的兴趣:
MoveMethod(搬移函数)、MoveField(搬移字段)
函数中只有一部分对其他类更感兴趣:
ExtractMethod(提炼函数)、MoveMethod(搬移函数)
判断哪个类拥有最多被此函数使用的数据,然后就把这个函数和那些数据放在一起
过度耦合的消息链(MessageChains)
a.getB().getC().getD().getE()……
存在一长串getThis()或一长串临时变量:
HideDelegate(隐藏“委托关系”)
中间人(MiddleMan)
过度运用委托(一半及以上的函数都委托给其他类):
RemoveMiddleMan(移除中间人)
如果“不干实事”的函数只有少数几个:
InlineMethod(内联函数)
如果中间人还有其他行为,需要对原对象的行为进行扩展:
ReplaceDelegationwithInheritance(以继承取代委托)
发散式变化(DivergentChange)
如果某个类经常因为不同的原因在不同的方向上发生变化【找出某特定原因而造成的所有变化】:
霰弹式修改(ShotgunSurgery)
把所有需要修改的代码放进同一个类中:
如果眼下没有合适的类可以安置这些代码,就创造一个
把一系列相关行为放进同一个类中:
平行继承体系(ParallelInheritanceHierarchies)
让一个继承体系的实例引用另一个继承体系的实例:
不完美的库类(IncompleteLibraryClass)
如果只想修改库类的一两个函数:
IntroduceForeignMethod(引入外加函数)
如果想要添加一大堆额外行为:
IntroduceLocalExtension(引入本地扩展)
过长参列()
向已有对象发出一条请求就可以取代一个参数:
ReplaceParameterwithMethod(以函数取代参数)
参数缺乏合理的对象归属:
IntroduceParameterObject(引入参数对象)
将来自同一个对象的一堆参数收集起来:
PreserveWholeObject(保持对象完整)
夸夸其谈的未来性(SpeculativeGenerality)
某个抽象类没有太大作用:
不必要的委托:
函数的某些参数未被使用:
RemoveParameter(移除参数)
函数名称带有多余的抽象涵义:
对于无用的函数:
InlineMethod(内联函数)、RemoveMethod(移除函数)
2.选取一款代码味道识别工具和实验项目进行代码味道识别实验,记录如下信息:
(1)代码味道检测工具名称:
PMD
(2)实验项目名称【至少1个】:
happychatroom
(3)实验结果:
代码味道数量
代码味道实例【类名或者代码片段,如果存在该代码味道的话至少需提供1个实例】
重复代码
134
Founda95line(286tokens)duplicationinthefollowingfiles:
Startingatline52ofC:
\软件配置实验\《软件配置管理\HappyChatRoom\src\cn\csu\chatRoom\controller\net\server\ServerFrame.java
Startingatline62ofC:
\软件配置实验\《软件配置管理\HappyChatRoom\src\cn\csu\chatRoom\src\Test\ServerFrame.java
ServerTransactiontransact=newServerTransaction();
/**
*Auto-generatedmainmethodtodisplaythisJFrame
*/
publicstaticvoidmain(String[]args){
SwingUtilities.invokeLater(newRunnable(){
publicvoidrun(){
ServerFrameinst=newServerFrame();
inst.setLocationRelativeTo(null);
inst.setVisible(true);
inst.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
publicServerFrame(){
super("
服务端"
);
initGUI();
privatevoidinitGUI(){
try{
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
{
jPanel1=newJPanel();
getContentPane().add(jPanel1,BorderLayout.CENTER);
jPanel1.setLayout(null);
{
jTextField1=newJTextField();
jPanel1.add(jTextField1);
jTextField1.setBounds(47,199,187,24);
jTextField1.addActionListener(this);
}
jButton1=newJButton();
jPanel1.add(jButton1);
jButton1.setText("
\u91cd\u65b0\u6765\u4e00\u6b21"
jButton1.setBounds(294,199,74,24);
jButton1.addActionListener(this);
jButton2=newJButton();
jPanel1.add(jButton2);
jButton2.setText("
\u5173\u95ed\u7ebf\u7a0b"
jButton2.setBounds(294,164,62,24);
jButton2.addActionListener(this);
jScrollPane1=newJScrollPane();
jPanel1.add(jScrollPane1);
jScrollPane1.setBounds(47,30,316,114);
{
jTextPane1=newJTextPane();
jScrollPane1.setViewportView(jTextPane1);
jTextPane1.setBounds(46,30,313,111);
jTextPane1.setEditable(false);
}
pack();
setSize(400,300);
}catch(Exceptione){
e.printStackTrace();
}
privatevoidreSetUp(){
server=newServerSocket(8765);
insert("
SetUP!
Waitforyou.."
listenT.start();
}catch(UnknownHostExceptione){
//TODOAuto-generatedcatchblock
}catch(IOExceptione){
3.使用EclipseRefactor菜单,掌握一些常用的重构操作,并在实验项目中选取合适的代码实施重构,填写如下表格:
重构名称
重构之前代码
重构之后代码
Rename
PublicclassChatRecordOper{
publicChatRecordOper(Stringpath){
}
publicvoidwrite(Stringt){
publicclassChatRecord{
publicChatRecord(Stringpath){
publicvoidwrite(Stringt){
Move
PrivatedoublegetCharge(doublepriceAmount,Purchasepurchase){
Returnpurchase.getCharge(priceAmount);
PublicclassPurchase{
PrivateBookbook;
Purchase(Bookbook){
This.book=book;
PublicBookgetBook(){
Returnthis.book;
PublicdoublegetCharge(doublepriceAmount){
priceAmount+=(float)getBook().getBookPrice()*getBook().getDiscount();
ReturnpriceAmount;
ChangeMethodSignature
PublicChatRecord(Stringpath){
publicChatRecord(Stringpath){
publicvoidwriter(Stringt){
Extracemethod
publicstaticvoidsetForeground(JEditorPaneeditor,Colorfg){
if(editor!
=null){
if(fg!
MutableAttributeSetattr=newSimpleAttributeSet();
StyleConstants.setForeground(attr,fg);
setCharacterAttributes(editor,attr,false);
}else{
UIManager.getLookAndFeel().provideErrorFeedback(editor);
setGround(editor,fg);
privatestaticvoidsetGround(JEditorPaneeditor,Colorfg){
StyleConstants.setForeground(