- 浏览: 150188 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
EclipseEye:
fair_jm 写道不错 蛮详细的 谢谢分享
SWT/JFace专题 --- SWT中Display和多线程 -
fair_jm:
不错 蛮详细的 谢谢分享
SWT/JFace专题 --- SWT中Display和多线程
敏捷这本书中,对重构的概念并没有深入,仅举了一个简单的例,既然提到了重构,又是如此重要的一个概念,下面的就结合《重构-改善既有代码的设计》这本书及网上的关于重构的资料,结合自己的理解,对“重构”这一概念做如下整理。
《重构-改善既有代码的设计》
记住所有的“坏味道”,记住它们对应的重构手法,记住常见的重构步骤,然后才能有信心面对各种复杂的情况。所以这本书需要结合实践,一遍一遍的阅读、琢磨、体会,才能练就重构的最高境界。
1.什么是重构?
重构(refactoring):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
2.为何要重构?
1)重构改进软件设计
2)重构使软件更容易理解
3)重构帮助找到bug
4)重构提高编程速度
良好的设计是维持软件开发速度的根本。重构可以帮助我们更快速地开发软件,因为它阻止系统腐bai变质,它甚至还可以提高设计质量。
3.何时重构?
重构是随时随地进行的,在你发现代码坏味道的时候,就是重构的时候,
特别是以下几个时机:
1)添加功能时重构
很多时候当我们添加新功能时,旧有的代码结构不能很方便我们添加新的功能时,就需要考虑重构了。
2)修补错误时重构
调试过程中运用重构,多半是为了让代码更具有可读性。可读性提高了就更容易发现bug。
3)复审代码时重构
在定期的代码审查过程中,或者在对刚入队的新员工指导代码结构时,一旦发现臭味,立马重构。
-------------------------
4.代码中的坏味道
1)重复代码(Duplicated Code)
2)过长函数(Long Method)
3)过大的类(Large Class)
4)过长参数列(Long Parameter List)
5)发散式变化(Divergent Change)
就是会有多个原因引起一个类的变化。
6)霰弹式修改(Shotgun Surgery)
和发散式变化类似,过程刚好相反。是指每遇到一个变化,就要修改许多不同的类。
7)依恋情结(Feature Envy)
就是A类中的一个方法或多个方法,过度的依赖B类中的方法,这个时候就可以考虑把这些方法直接移入到B类中了。
8)数据泥团(Data Clumps)
当类中的字段和参数过多时,就可以考虑新建一个数据类了。
9)基本类型偏执(Primitive Obsession)
这时可以考虑把基类变成对象了
10)switch惊秫现身(Switch Statements)
当出现过度的switch现象后,就可以考虑以多态的形式替换它们了。
11)平行继承体系(Parallel Inheritance Hierarchies)
是Shotgun Surgery的特殊情况,就是每当为某个类增加一个子类,必须也为另一个类相应的增加一个子类。
12)冗赘类(Lazy Class)
13)夸夸其谈未来性(Speculative Generality)
14)令人迷惑的暂时字段(Temporary Field)
15)过度耦合的消息链(Message Chains)
16)中间人(Middle Man)
17)狎昵关系(Inappropriate Intimacy)
两个类的关系过于紧密,需要考虑重构这两个类的行为了。
18)异曲同工的类(Alternative Classes with Different Interfaces)
19)不完美的库类(Incomplete Library Class)
20)纯稚的数据类(Data Class)
数据类不能太单纯,应该需要赋予一定的责任才好。
21)被拒绝的遗赠(Refused Bequest)
子类不需要实现父类的接口时,可以考虑委托的形式代替继承
22)过多的注释(Comments)
------------------------
5.重构方法
1)重新组织你的函数
(1)Extract Method 将这段代码放进一个独立函数里,并让函数名称解释该函数的用途
(2)Inline Method 在函数调用点插入函数本体,然后移除该函数
(3)Inline Temp 将所有对该变量的引用动作,替换为对它赋值的那个表达式自身
(4)Replace Temp with Query 将这个表达式提炼到一个独立函数中
(5)Introduce Explaining Variable 将该复杂表达式(或其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途
(6)Split Temporary Variable 针对每次赋值,创造一个独立的、对应的临时变量
(7)Remove Assignments to Parameters 以一个临时变量取代该参数的赋值结果
(8)Replace Method with Method Object 将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的值域,
然后你就可以在同一个对象中将这个大型函数分解为数个小型函数
(9)Substitute Algorithm 将函数本体替换为另一个算法
2)在对象之间搬移特性
(1)Move Method 你的程序中,有个函数与其所驻class之外另一个class进行更多交流,调用后者,或被后者调用
(2)Move Filed 在target class建立一个new field,修改source field的所有用户,令它们改用new field
(3)Extract Class 建立一个新class,将相关的值域和函数从旧class搬移到新class
(4)Inline Class 将class的所有特性搬移到另一个class中,然后移除原class
(5)Hide Delegate 在server端(某个class)建立客户所需的所有函数,用以隐藏委托关系delegation
(6)Remove Middle Man 让客户直接调用delegate
(7)Introduce Forergn Method 在client class中建立一个函数,并以一个server class实体作为第一引数
你所使用的server class中需要一个额外函数,但你无法修改这个class
(8)Introduce Local Extension 建立一个新class,使它包含这些额外函数。
让这个扩展品成为source class的subclass(子类)或wrapper(外覆类)
3)重新组织数据
(1)Self Encapsulate Field 为这个值域设立getter和setter,并且只以这些函数来访问值域
(2)Replace Data Value with Object 将这笔数据项变成一个对象
(3)Change Value to Reference 将实值对象改为引用对象
(4)Change Reference to Value 将它变成一个value object
(5)Replace Array with Object 以对象替换数组,对于数组中的每个元素,以一个值域表示之
(6)Duplicate Observed Data 将该数据拷贝到一个domain object中,建立一个Observe模式,
用以对domain object和GUI object内的重复数据进行同步控制
(7)Change Unidirectional Association to Bidirectional 添加一个反向指针,并使修改函数能够同时更新两条连接
(8)Change Bidirectional Association to Unidirectional 去除不必要的关联
(9)Replace Magic Number with Symbolic Constant 以符号常量/字面常量取代魔法数
(10)Encapsulate Field 将它声明为private,并提供相应的访问函数
(11)Encapsulate Collection 让这个函数返回该群集的一个只读映件,并在这个class中提供add/remove群集元素的函数
(12)Replace Record with Data Class 为该record记录创建一个哑数据对象dumb data object
(13)Replace Type Code with Class 以一个新的class替换该数值型别码
(14)Replace Type Code with Subclasses 以子类取代型别码(immutable type code)
(15)Replace Type Code with State/Strategy 以State/Strategy取代型别码
(16)Replace Subclass with Fields 修改这些函数,使它们返回subclass中的某个(新增)值域,然后销毁subclass
4)简化条件表达式
(1)Decompose Conditional 从if、then、else三个段落中分别提炼出独立函数
(2)Consolidate Conditional Expression 将这些测试合并为一个条件式,并将这个条件式提炼成为一个独立函数
(3)Consolidate Duplicate Conditional Fragments 将这段重复代码搬移到条件式之外
(4)Remove Control Flag 以break语句或return语句取代控制标记
(5)Replace Nested Conditional with Guard Clauses 使用卫语句取代嵌套条件式
(6)Replace Condional with Polymorphism 以多态取代条件式
(7)Introduce Null Object 将null value无效值 替换为null object无效物
(8)Introduce Assertion 以assersion明确表现这种假设
5)简化函数调用
(1)Rename Method 重新命名函数
(2)Add Parameter 添加参数
(3)Remove Parameter 移除参数
(4)Separate Query from Modifier 建立两个不同的函数,其中一个负责查询,另一个负责修改
(5)Parameterize Method 建立单一函数,以参数表达那些不同的值
(6)Replace Parameter with Explicit Methods 针对该参数的每一个可能值,建立一个独立函数
(7)Preserve Whole Object 改使用传递整个对象
(8)Replace Parameter with Methods 让参数接收者去除该项参数,并直接调用前一个函数
(9)Introduce Parameter Object 以一个对象取代这些参数
(10)Remove Setting Method class中的某个值域,应该在对象创建时被设值,然后就不再改变
(11)Hide Method 有一个函数,从来没有被其他任何class用到
(12)Replace Constructor with Factory Method 以工厂函数取代构造函数
(13)Encapsulate Dowmcast 将向下转型动作移到函数中
(14)Replace Error Code with Exception 以异常取代错误码
(15)Replace Exception with Test 以测试取代异常
6)处理概括关系
(1)Pull Up Field 值域上移
(2)Pull Up Method 函数上移
(3)Pull Up Constructor Body 构造函数本体上移
(4)Push Down Method 函数下移
(5)Push Down Field 值域下移
(6)Extract Subclass 提炼子类
(7)Extract Superclass 提炼超类
(8)Extract Interface 提炼接口
(9)Collapse Hierarchy 折叠继承体系
(10)Form Template Method 塑造模板函数
(11)Replace Inheritance with Delegation 以委托取代继承
(12)Replace Delegation with Inheritance 以继承取代委托
7)大型重构
(1)Tease Apart Inheritance 梳理并分解继承体系;
建立两个继承体系,同时承担两项责任
(2)Convert Procedural Design to Objects 将过程化设计转化为对象设计;
将数据记录变成对象,将行为分开,并将行为移入相关对象之中
(3)Separate Domain from Presentation 将领域和显示分离
将domain logic分离出来,为它们建立独立的domain classes
(4)Extract Hierarch 提炼继承体系
建立继承体系,以一个subclass表示一种特殊情况
---------------
写在后面:
这种类型的思想性书籍,读一遍两遍是没感觉的,需要结合实践,根据其给出的“坏味道”类别及相关的解决办法的列表,结合自己代码的实际需求,做适当的重构,体现的精神就是“适当”,过犹不及。
《重构-改善既有代码的设计》
记住所有的“坏味道”,记住它们对应的重构手法,记住常见的重构步骤,然后才能有信心面对各种复杂的情况。所以这本书需要结合实践,一遍一遍的阅读、琢磨、体会,才能练就重构的最高境界。
1.什么是重构?
重构(refactoring):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
2.为何要重构?
1)重构改进软件设计
2)重构使软件更容易理解
3)重构帮助找到bug
4)重构提高编程速度
良好的设计是维持软件开发速度的根本。重构可以帮助我们更快速地开发软件,因为它阻止系统腐bai变质,它甚至还可以提高设计质量。
3.何时重构?
重构是随时随地进行的,在你发现代码坏味道的时候,就是重构的时候,
特别是以下几个时机:
1)添加功能时重构
很多时候当我们添加新功能时,旧有的代码结构不能很方便我们添加新的功能时,就需要考虑重构了。
2)修补错误时重构
调试过程中运用重构,多半是为了让代码更具有可读性。可读性提高了就更容易发现bug。
3)复审代码时重构
在定期的代码审查过程中,或者在对刚入队的新员工指导代码结构时,一旦发现臭味,立马重构。
-------------------------
4.代码中的坏味道
1)重复代码(Duplicated Code)
2)过长函数(Long Method)
3)过大的类(Large Class)
4)过长参数列(Long Parameter List)
5)发散式变化(Divergent Change)
就是会有多个原因引起一个类的变化。
6)霰弹式修改(Shotgun Surgery)
和发散式变化类似,过程刚好相反。是指每遇到一个变化,就要修改许多不同的类。
7)依恋情结(Feature Envy)
就是A类中的一个方法或多个方法,过度的依赖B类中的方法,这个时候就可以考虑把这些方法直接移入到B类中了。
8)数据泥团(Data Clumps)
当类中的字段和参数过多时,就可以考虑新建一个数据类了。
9)基本类型偏执(Primitive Obsession)
这时可以考虑把基类变成对象了
10)switch惊秫现身(Switch Statements)
当出现过度的switch现象后,就可以考虑以多态的形式替换它们了。
11)平行继承体系(Parallel Inheritance Hierarchies)
是Shotgun Surgery的特殊情况,就是每当为某个类增加一个子类,必须也为另一个类相应的增加一个子类。
12)冗赘类(Lazy Class)
13)夸夸其谈未来性(Speculative Generality)
14)令人迷惑的暂时字段(Temporary Field)
15)过度耦合的消息链(Message Chains)
16)中间人(Middle Man)
17)狎昵关系(Inappropriate Intimacy)
两个类的关系过于紧密,需要考虑重构这两个类的行为了。
18)异曲同工的类(Alternative Classes with Different Interfaces)
19)不完美的库类(Incomplete Library Class)
20)纯稚的数据类(Data Class)
数据类不能太单纯,应该需要赋予一定的责任才好。
21)被拒绝的遗赠(Refused Bequest)
子类不需要实现父类的接口时,可以考虑委托的形式代替继承
22)过多的注释(Comments)
------------------------
5.重构方法
1)重新组织你的函数
(1)Extract Method 将这段代码放进一个独立函数里,并让函数名称解释该函数的用途
(2)Inline Method 在函数调用点插入函数本体,然后移除该函数
(3)Inline Temp 将所有对该变量的引用动作,替换为对它赋值的那个表达式自身
(4)Replace Temp with Query 将这个表达式提炼到一个独立函数中
(5)Introduce Explaining Variable 将该复杂表达式(或其中一部分)的结果放进一个临时变量,以此变量名称来解释表达式用途
(6)Split Temporary Variable 针对每次赋值,创造一个独立的、对应的临时变量
(7)Remove Assignments to Parameters 以一个临时变量取代该参数的赋值结果
(8)Replace Method with Method Object 将这个函数放进一个单独对象中,如此一来局部变量就成了对象内的值域,
然后你就可以在同一个对象中将这个大型函数分解为数个小型函数
(9)Substitute Algorithm 将函数本体替换为另一个算法
2)在对象之间搬移特性
(1)Move Method 你的程序中,有个函数与其所驻class之外另一个class进行更多交流,调用后者,或被后者调用
(2)Move Filed 在target class建立一个new field,修改source field的所有用户,令它们改用new field
(3)Extract Class 建立一个新class,将相关的值域和函数从旧class搬移到新class
(4)Inline Class 将class的所有特性搬移到另一个class中,然后移除原class
(5)Hide Delegate 在server端(某个class)建立客户所需的所有函数,用以隐藏委托关系delegation
(6)Remove Middle Man 让客户直接调用delegate
(7)Introduce Forergn Method 在client class中建立一个函数,并以一个server class实体作为第一引数
你所使用的server class中需要一个额外函数,但你无法修改这个class
(8)Introduce Local Extension 建立一个新class,使它包含这些额外函数。
让这个扩展品成为source class的subclass(子类)或wrapper(外覆类)
3)重新组织数据
(1)Self Encapsulate Field 为这个值域设立getter和setter,并且只以这些函数来访问值域
(2)Replace Data Value with Object 将这笔数据项变成一个对象
(3)Change Value to Reference 将实值对象改为引用对象
(4)Change Reference to Value 将它变成一个value object
(5)Replace Array with Object 以对象替换数组,对于数组中的每个元素,以一个值域表示之
(6)Duplicate Observed Data 将该数据拷贝到一个domain object中,建立一个Observe模式,
用以对domain object和GUI object内的重复数据进行同步控制
(7)Change Unidirectional Association to Bidirectional 添加一个反向指针,并使修改函数能够同时更新两条连接
(8)Change Bidirectional Association to Unidirectional 去除不必要的关联
(9)Replace Magic Number with Symbolic Constant 以符号常量/字面常量取代魔法数
(10)Encapsulate Field 将它声明为private,并提供相应的访问函数
(11)Encapsulate Collection 让这个函数返回该群集的一个只读映件,并在这个class中提供add/remove群集元素的函数
(12)Replace Record with Data Class 为该record记录创建一个哑数据对象dumb data object
(13)Replace Type Code with Class 以一个新的class替换该数值型别码
(14)Replace Type Code with Subclasses 以子类取代型别码(immutable type code)
(15)Replace Type Code with State/Strategy 以State/Strategy取代型别码
(16)Replace Subclass with Fields 修改这些函数,使它们返回subclass中的某个(新增)值域,然后销毁subclass
4)简化条件表达式
(1)Decompose Conditional 从if、then、else三个段落中分别提炼出独立函数
(2)Consolidate Conditional Expression 将这些测试合并为一个条件式,并将这个条件式提炼成为一个独立函数
(3)Consolidate Duplicate Conditional Fragments 将这段重复代码搬移到条件式之外
(4)Remove Control Flag 以break语句或return语句取代控制标记
(5)Replace Nested Conditional with Guard Clauses 使用卫语句取代嵌套条件式
(6)Replace Condional with Polymorphism 以多态取代条件式
(7)Introduce Null Object 将null value无效值 替换为null object无效物
(8)Introduce Assertion 以assersion明确表现这种假设
5)简化函数调用
(1)Rename Method 重新命名函数
(2)Add Parameter 添加参数
(3)Remove Parameter 移除参数
(4)Separate Query from Modifier 建立两个不同的函数,其中一个负责查询,另一个负责修改
(5)Parameterize Method 建立单一函数,以参数表达那些不同的值
(6)Replace Parameter with Explicit Methods 针对该参数的每一个可能值,建立一个独立函数
(7)Preserve Whole Object 改使用传递整个对象
(8)Replace Parameter with Methods 让参数接收者去除该项参数,并直接调用前一个函数
(9)Introduce Parameter Object 以一个对象取代这些参数
(10)Remove Setting Method class中的某个值域,应该在对象创建时被设值,然后就不再改变
(11)Hide Method 有一个函数,从来没有被其他任何class用到
(12)Replace Constructor with Factory Method 以工厂函数取代构造函数
(13)Encapsulate Dowmcast 将向下转型动作移到函数中
(14)Replace Error Code with Exception 以异常取代错误码
(15)Replace Exception with Test 以测试取代异常
6)处理概括关系
(1)Pull Up Field 值域上移
(2)Pull Up Method 函数上移
(3)Pull Up Constructor Body 构造函数本体上移
(4)Push Down Method 函数下移
(5)Push Down Field 值域下移
(6)Extract Subclass 提炼子类
(7)Extract Superclass 提炼超类
(8)Extract Interface 提炼接口
(9)Collapse Hierarchy 折叠继承体系
(10)Form Template Method 塑造模板函数
(11)Replace Inheritance with Delegation 以委托取代继承
(12)Replace Delegation with Inheritance 以继承取代委托
7)大型重构
(1)Tease Apart Inheritance 梳理并分解继承体系;
建立两个继承体系,同时承担两项责任
(2)Convert Procedural Design to Objects 将过程化设计转化为对象设计;
将数据记录变成对象,将行为分开,并将行为移入相关对象之中
(3)Separate Domain from Presentation 将领域和显示分离
将domain logic分离出来,为它们建立独立的domain classes
(4)Extract Hierarch 提炼继承体系
建立继承体系,以一个subclass表示一种特殊情况
---------------
写在后面:
这种类型的思想性书籍,读一遍两遍是没感觉的,需要结合实践,根据其给出的“坏味道”类别及相关的解决办法的列表,结合自己代码的实际需求,做适当的重构,体现的精神就是“适当”,过犹不及。
发表评论
-
也读《敏捷软件开发》--- OOP原则
2013-03-17 21:46 793面向对象程序设计(OOP ... -
也读《敏捷软件开发》--- 极限编程
2013-03-16 20:27 739写在前面: 像书中提到 ... -
【读书笔记】--敏捷软件开发
2013-02-18 01:32 0【读书笔记】--敏捷软件开发 -
也读《敏捷软件开发》--- 敏捷原则
2013-03-16 15:39 544《敏捷软件开发--原则 ... -
常用设计模式----复合模式
2013-02-13 02:26 667package org.design.patterns; ... -
常用设计模式----代理模式
2013-02-13 02:26 508package org.design.patterns; ... -
常用设计模式----状态模式
2013-02-13 02:25 542package org.design.patterns; ... -
常用设计模式----迭代器与组合模式
2013-02-12 13:04 759package org.design.patterns; ... -
常用设计模式----模板方法模式
2013-02-12 13:04 588package org.design.patterns; ... -
常用设计模式----适配器与外观模式
2013-02-12 13:04 735package org.design.patterns; ... -
常用设计模式----命令模式
2013-02-12 13:03 749package org.design.patterns; ... -
常用设计模式----装饰者模式
2013-02-12 13:03 743package org.design.patterns; ... -
常用设计模式----观察者模式
2013-02-11 12:11 693观察者模式: 定义了对 ... -
常用设计模式----工厂设计模式
2013-02-11 12:11 594package org.design.patterns; ... -
常用设计模式----单例模式
2013-02-11 12:10 669package org.design.patterns; / ... -
常用设计模式----策略模式
2013-02-11 12:10 739package org.design.patterns; ...
相关推荐
【敏捷软件开发第三讲——重构】是广州大学华软软件学院软件工程系的一堂课程,主讲教师谭翔纬在课件中详细介绍了重构的概念、原则、技巧以及它在软件开发中的重要性。 **重构介绍** 重构是软件开发中的一个重要...
《敏捷软件开发:原则、模式与实践》是Robert C. Martin(也被业界称为Uncle Bob)的经典著作,这本书深入探讨了敏捷开发的核心理念、最佳实践和实用技术,特别是在C#编程语言环境下的应用。以下是对该书主要内容的...
《敏捷软件开发:原则模式与实践》由享誉全球的软件开发专家和软件工程大师Robert C.Martin将向您展示如何解决软件开发人员、项目经理及软件项目领导们所面临的zui棘手的问题。这本综合性、实用性的敏捷开发和极限...
《敏捷软件开发——原则、模式与实践》是软件开发领域中一本深具影响力的著作,它由Robert C. Martin(简称Uncle ...《敏捷软件开发——原则、模式与实践》不仅是一本指南,也是推动软件开发领域持续进化的思想源泉。
本书《敏捷软件开发:原则、模式与实践》是由全球知名的软件开发专家和软件工程大师Robert C. Martin所著,该书是关于敏捷开发与极限编程的综合性、实用性指南。书中深入探讨了软件开发人员、项目经理以及软件项目...
《敏捷软件开发:原则、模式与实践(C#版)》是软件开发领域的一本经典著作,由Robert C. Martin撰写。这本书详细介绍了敏捷开发的理念、原则和实践方法,并结合C#编程语言提供了丰富的示例。以下是该书涵盖的一些...
XP是一种敏捷软件开发方法,它在预算和时间限制下,教导开发人员如何利用迭代计划、持续集成、测试驱动开发、重构和结对编程来完成软件项目。 敏捷宣言是敏捷运动的基石,提出了一系列价值和原则。宣言中强调了个体...
敏捷软件开发原则、模式与实践的知识,不仅适用于软件开发人员,也适用于项目经理、软件工程师以及软件架构师等。对于高校计算机专业本科生、研究生和软件学院的师生而言,这本书可以作为学习敏捷开发、极限编程、...
敏捷软件开发的优秀实践包括结对编程、测试驱动开发、客户参与验收、计划游戏、代码集体所有、每日站立会议、产品backlog、燃烧图、迭代计划会议、回顾会议、Scrum Master、Product Owner、Anatomy、One Track、...
敏捷软件开发模型--Scrum知识点详解: 一、敏捷开发与Scrum 敏捷开发是一种以人为核心、迭代、循序渐进的软件开发方法。敏捷宣言中提出的四大价值观是敏捷开发的核心,即个体和互动高于流程和工具,可用的软件高于...
### 敏捷软件开发知识点详解 #### 一、敏捷软件开发概述 **敏捷软件开发**是一种以人为本、迭代渐进的软件开发方法论。其核心在于快速应对变化,并通过高效的团队协作来实现高质量的软件产品。 #### 二、敏捷的...
《敏捷软件开发——原则、模式与实践》是软件工程领域一本经典的著作,它深入探讨了敏捷方法论在软件开发中的应用。源代码是书中理论与实践相结合的重要载体,提供了具体的实现示例,帮助读者更好地理解和掌握敏捷...
敏捷软件开发是现代软件工程领域的一项重要实践,它倡导快速迭代、持续集成和对变化的迅速响应。敏捷软件开发的主要目的在于提高软件质量和交付速度,同时更好地满足客户需求和应对变化。敏捷开发的核心是一系列原则...
《敏捷软件开发:原则、模式与实践》是Robert C. Martin(简称Uncle Bob)的一部经典著作,这本书深入探讨了敏捷开发的理念、方法和工具,尤其针对C#编程语言进行了详细阐述。作为一本实践导向的技术书籍,它旨在...
【敏捷软件开发C#版源码】是针对C#编程语言的一个实践项目,它与《敏捷软件开发》这本书紧密关联,旨在帮助读者更好地理解和应用敏捷开发的理念和方法。敏捷开发是一种以人为本、迭代、增量的软件开发方法论,强调...