7个软件开发原则
程序设计6大原则

程序设计6大原则程序设计是计算机科学中的重要领域,涵盖了开发、测试和维护计算机程序的过程。
为了编写高质量、可扩展、可维护的程序,程序员们必须遵循一些基本的原则。
在本文中,我将介绍6个程序设计的重要原则,它们是:单一责任原则、开闭原则、里氏替换原则、依赖倒置原则、接口隔离原则和最少知识原则。
一、单一责任原则单一责任原则(SRP)是指一个类应该只有一个引起它变化的原因。
换句话说,一个类只应该有一种职责,这样可以减少类的复杂性,并且使得类更加易于维护和测试。
通过将不同的功能拆分到不同的类中,可以实现单一职责原则。
这样的设计可以提高代码的可读性和可维护性。
二、开闭原则开闭原则(OCP)是指软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。
这意味着在向系统中添加新功能时,不应该修改已有的代码,而是通过扩展现有代码来实现新的功能。
这样的设计可以减少对原有代码的影响,提高系统的稳定性和可维护性。
三、里氏替换原则里氏替换原则(LSP)是指子类必须能够替换其父类,并且在替换后不会导致程序的错误或异常。
这意味着子类应该完全符合其父类的契约,不能改变父类已经定义的行为。
这样的设计可以确保代码的可靠性和可扩展性。
四、依赖倒置原则依赖倒置原则(DIP)是指高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
这意味着开发人员应该通过抽象接口来编程,而不是具体的实现类。
通过这种方式,可以减少模块之间的耦合,提高系统的灵活性和可测试性。
五、接口隔离原则接口隔离原则(ISP)是指客户端不应该依赖于它不需要的接口。
一个类不应该强迫其客户端实现那些它们不需要的方法。
这意味着开发人员应该将大的接口拆分为多个小的接口,以满足客户端的需求。
这样的设计可以减少代码的冗余,并且提高系统的可维护性和可扩展性。
六、最少知识原则最少知识原则(LOD)是指一个类不应该知道太多关于其他类的细节。
一个类应该尽可能少地了解其他类的方法和属性。
这样的设计可以减少类之间的依赖关系,提高系统的灵活性和可扩展性。
使用软件设计原则指导代码开发

使用软件设计原则指导代码开发软件设计原则是指导软件开发过程中遵循的一系列准则和规范,其目的是提高代码的可读性、可维护性和可扩展性。
下面将介绍常见的五个软件设计原则,并且说明如何应用它们来指导代码的编写。
1.单一职责原则(Single Responsibility Principle, SRP)单一职责原则是指一个类或模块应该有且只有一个单一的责任。
这意味着一个类应该只负责一项任务或功能,而不是包含多个不相关的功能。
当一个类承担了过多的责任时,它将变得复杂难以维护。
因此,我们应该将一个类的功能细分为多个更小的类或模块。
举个例子,考虑一个图形绘制的程序。
按照单一职责原则,我们可以将绘制逻辑和用户界面逻辑分别放在不同的类中。
这样,当我们需要修改绘制逻辑时,只需要修改与之相关的类,而不会影响到其他部分。
2.开放封闭原则(Open-Closed Principle, OCP)开放封闭原则是指软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。
这意味着我们应该通过扩展现有代码来实现新的功能,而不是修改已有的代码。
这样做的好处是降低了代码的风险和测试成本。
一个典型的应用开放封闭原则的例子是使用接口来定义类之间的依赖关系。
当需要更换实现时,只需要实现新的接口,而不需要修改调用方代码。
这样可以避免因为修改已有代码而引入新的问题。
3.里氏替换原则(Liskov Substitution Principle, LSP)里氏替换原则是指任意一个子类的实例都可以替换其父类的实例,而程序的行为不变。
换句话说,子类型必须能够替代其基类型,而不会引发意外的错误或异常。
遵循里氏替换原则可以增强代码的可扩展性和复用性。
例如,当我们设计一个基类时,我们应该确保所有的子类都能正确地继承和使用基类的方法和属性。
4.依赖倒置原则(Dependency Inversion Principle, DIP)依赖倒置原则是指高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
软件系统设计开发原则

1软件系统设计开发原则1.1系统标准化原则系统架构设计开始之前必须严格执行国家相关标准或行业标准设计,选择适合的业内标准的成熟技术体系和设计方法来规范和约束软件平台和软件体系结构,并遵循国际标准、国际通用惯例或计算机领域的通用规范。
最大程度保证系统具备各种层次的标准规范。
1.2可靠性原则软件系统规模越做越大越复杂,其可靠性越来越难保证。
应用本身对系统运行的可靠性要求越来越高,软件系统的可靠性也直接关系到设计自身的声誉和生存发展竞争能力。
软件可靠性意味着该软件在测试运行过程中避免可能发生故障的能力,且一旦发生故障后,具有解脱和排除故障的能力。
软件可靠性和硬件可靠性本质区别在于:后者为物理机理的衰变和老化所致,而前者是由于设计和实现的错误所致。
故软件的可靠性必须在设计阶段就确定,在生产和测试阶段再考虑就困难了。
健壮性是指软件对于规范要求以外的输入能够判断出这个输入是否符合规范要求,并能有合理的处理方式。
软件健壮性是一个比较模糊的概念,但是却是非常重要的软件外部量度标准。
软件设计的健壮与否直接反应了分析设计和编码人员的水平。
1.3坚持进行阶段评审软件的质量保证工作不能等到编码阶段结束之后再进行。
在每个阶段都进行严格的评审,以便尽早发现在软件开发过程中所犯的错误,是一条必须遵循的重要原则。
1.4实行严格的产品控制在软件开发过程中不应随意改变需求,因为改变一项需求往往需要付出较高的代价,但是,在软件开发过程中改变需求又是难免的,由于外部环境的变化,相应地改变用户需求是一种客观需要,显然不能硬性禁止客户提出改变需求的要求,而只能依靠科学的产品控制技术来顺应这种要求。
也就是说,当改变需求时,为了保持软件各个配置成分的一致性,必须实行严格的产品控制,其中主要是实行基线配置,它们是经过阶段评审后的软件配置成分(各个阶段产生的文档或程序代码)。
基线配置管理也称为变动控制:一切有关修改软件的建议,特别是涉及到对基准配置的修改建议,都必须按照严格的规程进行评审,获得批准以后才能实施修改。
举例说明软件设计7原则

举例说明软件设计7原则1. 单一职责原则(Single Responsibility Principle,SRP)一个类或模块应该只有一个改变的原因。
即,一个类或模块应该只有一个责任。
举例:一个数据处理类,它的职责是读取数据、处理数据并将结果返回。
如果将文件读取和数据处理的责任放在同一个类中,这违反了单一职责原则。
应该将文件读取和数据处理分别封装到两个单独的类中。
2. 开放封闭原则(Open-Closed Principle,OCP)软件实体(类,模块,函数等)应该对扩展开放,对修改封闭。
举例:一段代码用于计算员工的薪水,其中有一个计算基础薪水的函数。
如果需要增加一个新的员工类型,只需要创建一个新的类来实现员工的新薪水计算逻辑,而不需要修改原有的计算基础薪水的函数。
3. 里氏替换原则(Liskov Substitution Principle,LSP)子类型必须能够替换其基类型。
即,如果一个类B是类A的子类,那么在任何使用类A的地方都可以用类B来替换。
举例:有一个基类Animal,派生出子类Cat和Dog。
在一个方法中,如果传入一个Animal对象作为参数,应该能够接受任何Animal的子类对象作为参数。
4. 依赖倒置原则(Dependency Inversion Principle,DIP)高层模块不应该依赖于低层模块,二者都应该依赖于抽象。
抽象不应该依赖于细节,细节应该依赖于抽象。
举例:有一个Logger类用于记录日志,该类应该依赖于一个抽象的日志接口,而不应该直接依赖于具体的文件日志类。
这样,在需要更换日志实现方式时,只需要创建一个新的实现了日志接口的类,无需修改Logger类。
5. 接口隔离原则(Interface Segregation Principle,ISP)客户端不应该依赖于它不需要的接口。
一个类不应该强迫其客户端依赖于它们不需要的方法。
举例:有一个图形类,它有用于绘制线条、绘制矩形、绘制圆形的方法。
java的设计原则

java的设计原则Java是一种广泛使用的编程语言,它的设计原则涉及到很多方面,包括可读性、可维护性、灵活性等。
本文将对Java的设计原则进行详细介绍。
一、SOLID原则SOLID原则是面向对象编程中的五个基本原则,它们分别是单一职责原则(SRP)、开放封闭原则(OCP)、里氏替换原则(LSP)、接口隔离原则(ISP)和依赖倒置原则(DIP)。
这些原则可以帮助我们设计出更加健壮、灵活和可扩展的代码。
1. 单一职责原则单一职责原则指一个类只负责一个功能或者任务。
这样可以提高代码的可读性和可维护性,同时也降低了类之间的耦合度。
2. 开放封闭原则开放封闭原则指软件实体应该对扩展开放,对修改关闭。
这意味着当需求发生变化时,我们不需要修改已有的代码,而是通过扩展来满足新需求。
3. 里氏替换原则里氏替换原则指子类可以替换掉父类并且不会影响程序的正确性。
这意味着在使用继承时,子类需要保持和父类一致的行为和约束。
4. 接口隔离原则接口隔离原则指一个类不应该依赖它不需要的接口。
这样可以避免因为接口改变而导致的代码修改。
5. 依赖倒置原则依赖倒置原则指高层模块不应该依赖低层模块,而是应该依赖其抽象。
这样可以降低模块之间的耦合度,提高代码的可复用性。
二、DRY原则DRY原则指“Don't Repeat Yourself”,即不要重复自己。
这意味着我们应该尽可能地避免重复代码,而是把相同或相似的功能抽象成一个公共部分,以提高代码的可维护性和可扩展性。
三、KISS原则KISS原则指“Keep It Simple, Stupid”,即保持简单。
这意味着我们应该尽量避免过度设计和复杂实现,而是采用简单明了的方式来解决问题,以提高代码的可读性和可维护性。
四、YAGNI原则YAGNI原则指“You Ain't Gonna Need It”,即你不会需要它。
这意味着我们应该尽可能地避免过度设计和实现,在真正需要时再进行扩展和修改,以提高代码的简洁性和可维护性。
程序设计七大原则

软件设计的七大原则设计模式遵循的一般原则:1.开-闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开发,对修改关闭.说的是,再设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展.换言之,应当可以在不必修改源代码的情况下改变这个模块的行为,在保持系统一定稳定性的基础上,对系统进行扩展。
这是面向对象设计(OOD)的基石,也是最重要的原则。
2.里氏代换原则(Liskov Substitution Principle,常缩写为.LSP)(1).由Barbar Liskov(芭芭拉.里氏)提出,是继承复用的基石。
(2).严格表达:如果每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都代换称o2时,程序P的行为没有变化,那么类型T2是类型T1的子类型.换言之,一个软件实体如果使用的是一个基类的话,那么一定适用于其子类,而且它根本不能察觉出基类对象和子类对象的区别.只有衍生类可以替换基类,软件单位的功能才能不受影响,基类才能真正被复用,而衍生类也能够在基类的基础上增加新功能。
(3).反过来的代换不成立(4).<墨子.小取>中说:"白马,马也; 乘白马,乘马也.骊马(黑马),马也;乘骊马,乘马也."(5).该类西方著名的例程为:正方形是否是长方形的子类(答案是"否")。
类似的还有椭圆和圆的关系。
(6).应当尽量从抽象类继承,而不从具体类继承,一般而言,如果有两个具体类A,B有继承关系,那么一个最简单的修改方案是建立一个抽象类C,然后让类A和B 成为抽象类C的子类.即如果有一个由继承关系形成的登记结构的话,那么在等级结构的树形图上面所有的树叶节点都应当是具体类;而所有的树枝节点都应当是抽象类或者接口.(7)."基于契约设计(Design By Constract),简称DBC"这项技术对LISKOV代换原则提供了支持.该项技术Bertrand Meyer伯特兰做过详细的介绍:使用DBC,类的编写者显式地规定针对该类的契约.客户代码的编写者可以通过该契约获悉可以依赖的行为方式.契约是通过每个方法声明的前置条件(preconditions)和后置条件(postconditions)来指定的.要使一个方法得以执行,前置条件必须为真.执行完毕后,该方法要保证后置条件为真.就是说,在重新声明派生类中的例程(routine)时,只能使用相等或者更弱的前置条件来替换原始的前置条件,只能使用相等或者更强的后置条件来替换原始的后置条件.3.依赖倒置原则(Dependence Inversion Principle),要求客户端依赖于抽象耦合.(1)表述:抽象不应当依赖于细节,细节应当依赖于抽象.(Program to an interface, not an implementaction)(2)表述二:针对接口编程的意思是说,应当使用接口和抽象类进行变量的类型声明,参量的类型声明,方法的返还类型声明,以及数据类型的转换等.不要针对实现编程的意思就是说,不应当使用具体类进行变量的类型声明,参量类型声明,方法的返还类型声明,以及数据类型的转换等.要保证做到这一点,一个具体的类应等只实现接口和抽象类中声明过的方法,而不应当给出多余的方法.只要一个被引用的对象存在抽象类型,就应当在任何引用此对象的地方使用抽象类型,包括参量的类型声明,方法返还类型的声明,属性变量的类型声明等. (3)接口与抽象的区别就在于抽象类可以提供某些方法的部分实现,而接口则不可以,这也大概是抽象类唯一的优点.如果向一个抽象类加入一个新的具体方法,那么所有的子类型一下子就都得到得到了这个新的具体方法,而接口做不到这一点.如果向一个接口加入了一个新的方法的话,所有实现这个接口的类就全部不能通过编译了,因为它们都没有实现这个新声明的方法.这显然是接口的一个缺点.(4)一个抽象类的实现只能由这个抽象类的子类给出,也就是说,这个实现处在抽象类所定义出的继承的登记结构中,而由于一般语言都限制一个类只能从最多一个超类继承,因此将抽象作为类型定义工具的效能大打折扣.反过来,看接口,就会发现任何一个实现了一个接口所规定的方法的类都可以具有这个接口的类型,而一个类可以实现任意多个接口.(5)从代码重构的角度上讲,将一个单独的具体类重构成一个接口的实现是很容易的,只需要声明一个接口,并将重要的方法添加到接口声明中,然后在具体类定义语句中加上保留字以继承于该接口就行了.而作为一个已有的具体类添加一个抽象类作为抽象类型不那么容易,因为这个具体类有可能已经有一个超类.这样一来,这个新定义的抽象类只好继续向上移动,变成这个超类的超类,如此循环,最后这个新的抽象类必定处于整个类型等级结构的最上端,从而使登记结构中的所有成员都会受到影响.(6)接口是定义混合类型的理想工具,所为混合类型,就是在一个类的主类型之外的次要类型.一个混合类型表明一个类不仅仅具有某个主类型的行为,而且具有其他的次要行为.(7)联合使用接口和抽象类:由于抽象类具有提供缺省实现的优点,而接口具有其他所有优点,所以联合使用两者就是一个很好的选择.首先,声明类型的工作仍然接口承担的,但是同时给出的还有一个抽象类,为这个接口给出一个缺省实现.其他同属于这个抽象类型的具体类可以选择实现这个接口,也可以选择继承自这个抽象类.如果一个具体类直接实现这个接口的话,它就必须自行实现所有的接口;相反,如果它继承自抽象类的话,它可以省去一些不必要的的方法,因为它可以从抽象类中自动得到这些方法的缺省实现;如果需要向接口加入一个新的方法的话,那么只要同时向这个抽象类加入这个方法的一个具体实现就可以了,因为所有继承自这个抽象类的子类都会从这个抽象类得到这个具体方法.这其实就是缺省适配器模式(Defaule Adapter).(8)什么是高层策略呢?它是应用背后的抽象,是那些不随具体细节的改变而改变的真理. 它是系统内部的系统____隐喻.4.接口隔离原则(Interface Segregation Principle, ISP) (1)一个类对另外一个类的依赖是建立在最小的接口上。
软件开发原则

软件开发原则
软件开发原则包括:
1. 尽早测试:确保运行正常,跟踪和测试软件在整个开发周期中的各个状态;
2. 迭代开发:通过分治,分解大型复杂系统,快速实现一个可行性原型,确保系统完成并不断改善;
3. KISS(Keep It Simple, Stupid)原则:避免复杂的设计,保持简单的设计和架构;
4. DRY(Do Not Repeat Yourself)原则:使用模块化编程以及其他技术来减少重复代码和信息;
5. YAGNI(You Aren't Gonna Need It)原则:只在需要时编写代码,在软件开发中合理规划每一步;
6. 模块化:将系统划分为独立的、可重复使用的组件,简化各模块之间的耦合;
7. 尽早发布:尽快发布原型或最小可用产品,以收集客户反馈以及优化后续版本;
8. 最小改动原则:尽量在不改变现有代码的情况下编写新的代码;
9. 遵循标准和规范:使用通用的编程语言和框架,遵循当前最佳实践标准和规范。
软件开发七大原则

软件开发七大原则软件开发七大原则如下:1. 单一职责原则(Single Responsibility Principle, SRP)单一职责原则是软件开发中最基本的原则之一,它要求一个类只应该有一个引起变化的原因。
也就是说,一个类应该只有一个职责,只有一个改变它的原因。
如果一个类承担了多个职责,那么就相当于把这些职责耦合在一起,当一个职责发生变化时,可能会影响到其他职责。
2. 开放封闭原则(Open Closed Principle, OCP)开放封闭原则是指软件实体(类、模块、函数等等)应当是可扩展,而不可修改的。
也就是说,新的功能应该通过添加新代码实现,而不是改变现有的代码。
开放封闭原则的核心思想是将软件实体设计成可扩展的,这样可以减少代码的维护量和修改量。
3. 里氏替换原则(Liskov Substitution Principle, LSP)里氏替换原则是指子类必须能够替换其父类。
也就是说,在软件中,如果我们用子类替换掉所有的父类实例,那么程序的行为还应该保持不变。
这个原则可以让我们避免在继承关系中产生破坏封装性的行为。
4. 接口隔离原则(Interface Segregation Principle, ISP)接口隔离原则是指使用多个特定的接口,而不使用单一的总接口,客户端不应该被强制依赖于它们不使用的接口。
这个原则可以降低类之间的耦合度,提高系统的可维护性和可扩展性。
5. 依赖倒置原则(Dependency Inversion Principle, DIP)依赖倒置原则是指要依赖于抽象,不要依赖于具体。
也就是说,实现类之间的依赖通过抽象(接口或抽象类)进行,而不是直接通过具体的类进行。
这个原则可以降低类之间的耦合度,提高系统的可维护性和可扩展性。
6. 迪米特法则(Law of Demeter, LoD)迪米特法则是指一个对象应当对其他对象保持最少的了解。
也就是说,每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
7个软件开发原则关于代码重复最著名的单词是Kent Beck的Once And Only Once,也就是说软件操作的任何一个片断--不管是一个算法,一个常量集合,用于阅读的文档或者其他东西--应当只出现一次。
软件重复出现至少会导致以下问题:·其中的一个版本会过期·代码的责任会四处散开,导致代码难以理解·当你修改代码时,需要重复修改很多地方,一不小心就会遗漏·你不能很好地进行性能优化重复代码的产生有各种各样的原因,程序员把几行或一整段代码从这里复制到这里,然后少加修改,就变成了一份新的代码。
这里的原因是程序员可以通过极少的努力就完成代码重用,但是我们可以来看看DavidHooker提出的7个软件开发原则:1.第一原则:存在的理由(Pattern: TheReason)一个软件系统存在的理由就是:为它的用户提供价值。
你所有的决定都取决于这一点。
在指定一个系统需求,在写下一段系统功能,在决定硬件平台和开发过程之前,问你自己一个问题,“这样做会为系统增加价值吗?“,如果答案是”yes”,做。
如果是”No”,不做。
这个原则是其他原则的原则。
2.第二原则(能简单就简单,愚蠢!)KISS (Pattern: KeepItSimple)软件设计不是一个轻描淡写的过程。
在做任何一个设计时,你必须考虑很多因素。
所有设计应当尽可能简单,但是不要再比这简单了。
这样产生的系统才是可以理解和容易维护的。
这并不是说很多由意义的特性,因为这种简单性也要被抛弃。
确实很多更优雅的设计往往更简单,但简单并不意味着“quick and dirty."。
事实上,简单是通过许多思考和一次一次的反复修改才达到的。
这些努力的汇报就是更容易维护,代码错误更少。
(看看是否违反)3.第三原则:保持远见(Pattern: MaintainTheVision)清晰的远见是一个软件项目成功的基础。
没有这样的远见,项目开发最后就变成天天为一个不好的设计做补丁。
Brooks说过:概念的完整性是系统设计中最重要的问题。
Stroustrup 也说:有一个干净的内部结构识构建一个可理解、可辨识、可维护、可测试系统的基础。
Booch则总结道:只有当你对系统的体系由一个清晰的感觉,才可能去发现通用的抽象和机制。
开发这种通用性最终导致系统更简单,因此更小,更可靠如果你不断地复制、粘贴、修改代码,最终你将陷入一个大泥潭(the Big Mud),你永远不可能对系统有一个清晰的认识。
4.第四原则:你制造的,别人会消费 (Pattern: WhatYouProduceTheyConsume)软件系统不是在真空中使用的。
其他人会使用、维护、文档你的系统。
这依赖于对你系统的理解。
所以,你设计、实现的东西应当能够让别人理解。
要记住,你写的代码并非只给计算机看,你要时时记住,代码还要给人看。
(Kent Beck) 如果到处泛滥似是而非的代码,别人如何能够辨别这些代码的相似和不同,如何去理解这些代码之间具有何种关系。
5.第五原则:对将来开放( Pattern BuildForTodayDesignForTomorrow)一个成功的软件有很长的生命期。
你必须能够使得软件能够适应这样和那样的变化。
所以,一开始就不要软件设计到死角上去。
请总是问一下自己“如果这样,那么。
?“这个问题,你要考虑到各种各样的可能性,而不光光是图省事。
复制,粘贴一下即可。
6.第六原则:为重用做好计划软件模式是重用计划的一种。
不断重复的代码显然不是这样的计划。
(See CommentsOnSix)7.第七原则:思考!在采取任何动作之前首先做一个清晰、完整的考虑,这样才能产生更好的结果。
如果你考虑了,但还是产生错误的结果,那么这种努力也是值得的。
在你学习或研究类似的问题时,更容易理解和掌握。
这些原则告诉我们轻松地复制、粘贴和修改代码不可能产生好的,也就是容易理解、维护、重用的代码。
但请不要走极端。
我一直认为,一个好的软件系统是各种因素权衡的结果,也就是你如何把握一个度的问题。
重复代码产生的另外一个主要原因就是做得太多,XP有一个基本原则叫做You Arent Gonna Need It,它是说“只实现你真正需要的东西,从来不去实现你预期需要的东西“。
如果你去实现你现在认为将来需要的东西,不一定就是你以后真正需要的东西。
你处于现在的环境中可能无法理解你要实现东西究竟是什么样子的。
你会浪费大量的时间去构造这样不知道是否必须的可能性。
同时,当你真正实现的时候就可能产生重复代码。
Martin Fowler在它的Refactoring一书中有很多用来处理代码重复,包括:1.同一个类的两个方法中有相同的表达式,使用Extract method,然后大家都调用该method;2.两个兄弟子类之间有相同的表达式,那么在这两个子类中使用Extract Method,接着使用pull up field,移到共同的超类3.如果结构相似而并非完全相同,用Extract method把相同部分和不同部分分开。
然后使用Form Template method. 4.如果方法使用不同的算法做相同的事情,那么使用substitute algorithm 5.如果在两个不相干的类中有重复代码,那么在一个类中使用Extract class,然后在其他类中使用该class 对象作为元素。
等等。
重复代码需要refactoring是毫无疑问的,关键在于,你如何找到重复代码,如果所有的重复代码都是死板的重复,那问题是很容易解决的。
但是软件开发的复杂因素可能往往使重复代码表现为相似性而并非完全的重复。
这些相似性可能并非一眼就能看出来。
而是需要经过其它的Refactory步骤和一定的先见之明。
另一个问题就是排除重复代码的粒度,只有大段的重复代码有价值去排除,还是即使是小小的2、3句重复代码就应该去排除。
重复代码排除的基本方法是建立自己单独的方法,如果系统中许许多多的方法都很小,方法之间相互调用的开销就会增加,它同时也增加了维护的开销。
但是,这些开销是值得的。
方法是覆盖的最小粒度,能够被覆盖的粒度越小,能够重用的范围和成都就愈广。
但在这个问题上也不要走极端,只有当一个方法实现一个具体的可以用Intent Revealing Name(揭示意图的名字)命名时,一段代码才值得称为一个方法,而不是考虑其代码的多少。
Martin Fowler在他的refactoring中描述了很多这样的例子,Kent Beck则在Smalltalk Best Practice Pattern中更基础地揭示了隐含在这些refactoing下的意图。
下面是一个实际的例子,来自于Martin Fowler在ACM上的设计专栏: class Invoice... String asciiStatement() { StringBuffer result = new StringBuffer();result.append(“Bill for “ + customer + “/n”);Iterator it = items.iterator(); while(it.hasNext()){LineItem each = (LineItem) it.next();result.append(“/t” + each.product() + “/t/t” + each.amount() + “/n”);} result.append(“total owed:” + total + “/n”);return result.toString();}String htmlStatement(){StringBuffer result = new StringBuffer();result.append(“ Bill for ” + customer + “”);result.append(“”);Iterator it = items.iterator();while(it.hasNext()){LineItem each = (LineItem) it.next();result.appen d(“” + each.product() + “” + each.amount() + “”);} result.append(“”);result.append(“ total owed:” + total + “”); return result.toString(); }}asciiStatement和htmlStatement具有类似的基础结构,但是它们的实际步骤却有所不同。
他们都完成三件事情:1.打印发票头2.循环每一个项目,并打印3.打印发票尾部这种结构的相似性和意图马上上我们使用composed method(也就是Martin Fowler的Extract method): interface Printer{String header(Invoice iv);String item(LineItem line);String footer(Invoice iv);}static class AsciiPrinter implements Printer{public String header(Invoice iv){return “Bill for “ + iv.customer + “/n”;}public String item(LineItem line){return “/t” + line.product()+ “/t/t” + line.amount() +“/n”;}public String footer(Invoice iv){return “total owed:” + iv.total + “/n”;}}象html则可以实现htmlPrinter. class Invoice... public String statement(Printer pr){StringBuffer result = new StringBuffer();result.append(pr.header(this));Iterator it = items.iterator();while(it.hasNext()){LineItem each = (LineItem) it.next();result.append(pr.item(each));}result.append(pr.footer(this));return result.toString();}class Invoice... public String asciiStatement2(){return statement (new AsciiPrinter());}现在,statement包含一个通用的结构,重复性已经被排除。