重用代码的目标是什么?(我们为什么要重用代码)
答:避免重复发明轮子,有大量的已经写好的功能可以调用.这也是OO(面向对象的目标)
什么样的代码是可以复用的代码?
1.接口良好的.(利于用户阅读和使用)
1).类的接口应该展现一致的抽象层次.
public class
EmpolyeeContainer extends LinkedList{
public void addEmpolyee(Empolyee e);//1
public void removeEmpolyee(Empolyee
e);//2
public Empolyee nextItem();//3
public Empolyee firstItem();//4
public Empolyee lastItem();//5
}
这个接口暴露了两层抽象1,2是Container操作,3,4,5是List操作.实际上我们只需要1,2.这里不应该用继承而应该使用组合.这样做会暴露内部的实现机制,造成客户调用的混乱,
public class EmpolyeeContains{
public void addEmpolyee(Empolyee e);//1
public void removeEmpolyee(Empolyee
e);//2
public Empolyee nextEmpolyee();
private LinkedList innerContainer ;//3
}
1,2的操作通过3的数据结构实现,但是接口本身不暴露内部的实现机制.暴露的内部细节越少越有利于修改.
2).提供成对(组)的服务.
3).尽可能让接口可编程,而不是表达语义.
暴露的接口应该仅仅通过编译器就能限制其使用方法,例如接口限定方法的参数类型,个数等等编译器可检查的错误.如果接口中有这样的方法step1(),step2(),隐含的表达step1必须在step2之前调用否则会出错,这种语义性的行为是编译器无法检查的.也就是说调用者有可能会调用错误.应该尽量避免这种接口设计,至少要通过注释文档说明这种语义.
commons-lang包中的StringUtils,这是个常用的字符串处理工具类,这是个设计很好的接口基本上每个方法的名字就说明了自己的行为,方法之间也没有语义的约束.而且方法往往分组,一些列的substringBetween,substringBefore,substringAfter.
2.代码是可读的.(利于用户和自己理解代码)
可以工作的代码,已经暴露的良好的接口,用户可以很方便的使用,而且他没必要了解内部实现,所以内部代码未必需要可读只要能工作就行.这种想法是错误(愚蠢)的.因为没有任何代码是一成不变的,需求总在变化,总有一天需要修改代码以适用新的需求,否则代码的生命周期就结束了也就不再可复用.
改善代码可读性的原则.
1).前面提到过的.统一的抽象层次有利于代码的阅读.
2).良好设计编码的子程序(方法)
只做一件事(单一职权原则)
这意味着方法不应该有副作用,考虑如下代码.
public boolean validateUser(User
user){
session.init();
if(user.getPassword().equals(password)){
return true ;
}else{
return false ;
}
}
问题就出在session.init().方法名并没有暗示,方法会初始化session.方法名可以改为initSessionAndValidateUser(User
user)但这依然违反了单一职权原则.但是却可以让用户清楚知道代码有这样的副作用.
方法不易过长.语句之间应保持统一的抽象(这个比较难做到,也难以理解).
30秒原则(任何方法如果在30秒内不能阅读理解,就应当做进一步拆分).
private HttpUriRequest
buildHttpPost() {
String
uri = uriPattern.replaceAll("\\?.*", "");//1
logger.info("POST请求:\n{}", uri);//2
HttpPost
req = new HttpPost(uri);//3
HttpEntity
entity = buildHttpEntity();//4
req.setEntity(entity);//5
return
req;
}
3,4,5处于统一抽象层次,每一句都是描述如何构建一个HTTP_POST请求.但是1,2就不是,他们描述的是如何得到正确的请求URI.这两句可以进一步拆分成createPostUri().但是目前为止方法本身符合30秒原则,所以可读性是可以接受的,但如果未来由于需求变化,要做进一步的修改时,这个方法就必须做进一步拆分.
参数的数量.
大多数情况下,无参数或单参数的情况最好.例外的情况比如Point(x,y)这样的方法,Point具有其自然属性,所以两个参数比较合适.对于单参数方法最好方法名与参数名形成动词/名词形式.例如write(name)这个方法如果写成writeField(name)那么调用者就很容易知道name是一个field.
标示参数,有些方法使用标示参数比如有这样一个方法newWriter(File file , boolean append)当append为true时新建的Writer会将内容附加到file中,否则清空原来的文件写入内容.这时起码就要阅读以下文档调用者才知道如何使用标示参数.这是可以采用拆分为两个方法来去掉这个标示参数.newWriter(File file),newAppendableWriter(File file).这样就一目了然了.
输出参数是不建议使用的,应该尽量使用返回值做为输出结果.
变量和方法名称应当有意义,做到代码本身就是自解释的.
推荐书籍<Clean
Code>代码整洁之道.代码大全,敏捷软件开发
3.遵循编码实践.
有很多编码的实践可以借鉴,以提高代码质量.例如经典的设计模式.(由于篇幅有限再次就不介绍了).在此只介绍一些我在日常工作中的体会.
1).面向接口编程,避免使用继承而使用对象组合.依赖倒置(依赖注入)
面向接口编程无疑可以减少对具体类的依赖,降低类之间的耦合.良好设计的接口是细小而稳定的,那么依赖接口可以减少对类的改变(符合开放封闭原则).
继承是OO中很方便的复用代码的方式,虽然Java只支持单继承,降低了继承的复杂度,但当继承层次增加,代码的可读性就会下降,内部细节也越复杂子类对父类的依赖和耦合也比较严重.特别是子类使用父类的保护成员和字段的时候,这样的类在阅读代码的时候是很晦涩的.
对象组合技术同样可以实现继承带来的功能(虽然有时要多些一些代码,但是可以让程序结构更简单灵活)
观察如下代码.
abstract class
AbstractExampleDocument
{
// skip some code ...
public void output(Example structure)
{
if( null !=
structure )
{
this.format( structure );
}
}
protected void format(Example structure);
}
当要实现自定义格式的时候只需要继承该类并覆盖format保护方法即可.此时由于需求变化要在该类中添加一个将格式化好的structure保存到数据库的功能.但父类不知道子类如何格式化structure所以无法确定保存到数据库的实现.可以考虑在父类中增加一个save()抽象方法,待子类去实现.天啊,所有的子类都要实现一次save()方法.而且所有的格式化操作和保存到数据库的操作是紧密耦合的.将structure保存到数据库的操作可能在很多地方都有用,但是却无法从子类中单独提取出来使用.
class DefaultExampleDocument
{
private Formatter formatter ;
public void setFormatter(Formatter formatter){
this.formatter
= formatter;
}
// skip some code ...
public void output(Example structure)
{
ExampleFormatter formatter =
(ExampleFormatter) manager.lookup(Roles.FORMATTER);
if(
null != structure )
{
formatter.format(structure);
}
}
}
使用对象组合技术,只需要再编写一个Saver放到DefaultExampleDocument 中,在output结束之前调用Saver的save方法即可应对上述变化需求.此时依赖注入出场了,什么样formatter对应什么样的saver完全交由依赖注入决定,而且硬编码在一起,解决了耦合问题.而且对DefaultExampleDocument 的修改完全不需要影响所有的formatter.
可见优先使用对象组合,和面向接口编程可以很好的利用依赖注入实现代码的解耦提高代码的可维护性和可扩展性.
继承也不是一定不要用的,当父类和子类有is-a关系时候,适合使用继承.使用继承时要注意符合替换原则(在任何时候子类实例都可以替换父类实例使用)
单一职权和开放封闭原则.
该原则要求代码对扩展是开放的,对修改是封闭的.最佳状态是一个类或者方法,只有一个引起变化的理由.当然要做到这一点首先就是要符合单一职权原则(只做一件事).符合单一职权原则才可以保证只要在要做的那件事的需求有变化的时候才会修改代码.否则只需要扩展代码.实现开放封闭的方式有很多,例如前面的对象组合技术,还有很多有关的设计模式Bridge,Composite,Decorator,Observer,Strategy等等.
case/if语句
这种语法是大多编程语言中的基本流程控制语句.常常造成过多的缩进,和过多的流程分支.而且这种语句难以拆分成小方法.严重影响代码的可读性.当分支过多时,是不是可以考虑使用查表法?
例如,在分析xml文件时对不同的标签初始化不同的对象实例
TagInstance instance ;
if(tag==A){
instance =
new A();
}else if(tag==B){
instance =
new B();
}else if(tag ==C){
instance =
new C() ;
}else{
instance =
new D();
}
可以替换为
Map map = new HashMap();
map.put(“A”,new A());
…
map.put(“D”,new D());
TagInstance instance = map.get(tag);
这样明显逻辑清楚而且很容易修改,代码量也下降了.也很容易进行方法拆分.
做到上述的代码就是可复用的好代码吗?未必,作为一个开发人员编写好代码是贯彻始终的,所有的实践均来源于自己和他人的经验总结,到底如何才能写出好的可复用的代码每个人的标准也不完全一致.在此只是提及了一些我认为是大多数人公认的原则和实践.
参考资料,代码整洁之道,代码大全,敏捷软件开发.
分享到:
相关推荐
**CMMI 代码复用报告模板详解** 代码复用是软件开发中的一项关键实践,旨在提高效率,减少错误,并促进代码的可维护性。CMMI(Capability Maturity Model Integration,能力成熟度模型集成)是衡量软件开发过程质量...
在Delphi编程环境中,代码复用是提高效率和软件质量的关键策略。代码复用不仅可以简化编码,减少工作量,还能促进团队协作,提高代码的可维护性和一致性。本文主要探讨了在只使用Delphi作为开发工具的情况下,如何...
本资料包“运用LabVIEW实现机器人中的代码复用.zip”主要关注如何利用LabVIEW提高开发效率,通过代码复用来缩短项目周期。 首先,代码复用是软件工程中的一个核心概念,旨在减少重复工作,提升开发速度和代码质量。...
### 第5章 函数和代码复用 #### 知识点概述 本章节主要围绕着函数的概念、定义、使用以及代码复用的方式展开讨论。针对Delphi环境下的Python语言程序设计,深入剖析了如何利用函数实现更高效、灵活的编程实践。 #...
《基于上下文的智能化代码复用推荐》\n\n代码复用是软件开发中的关键实践,旨在提升开发效率和代码质量。随着互联网的发展,代码大数据的积累为智能化代码复用推荐提供了新的可能性。本文主要探讨了两个核心方向:...
《基于上下文的智能化代码复用推荐》这篇文章探讨了如何利用现代技术和大数据分析来提高软件开发中的代码复用效率和质量。代码复用是开发者常用的一种高效开发手段,包括复用相似功能模块、代码片段以及API等不同...
在C++编程中,代码复用是提高效率和减少错误的关键。本项目“C++可复用代码——命令行控制模块”提供了一个基础框架,帮助开发者轻松构建自定义的命令行Shell程序。这个框架旨在使程序员能够专注于实现特定功能,而...
python函数及代码复用学习教案.pptx
这种机制使得代码复用变得简单,同时也促进了类的分层结构,有助于创建更复杂的系统。例如: ```cpp class Worker { public: void work() { // 工人的一般工作 } }; class AdvancedWorker : public Worker { ...
【运行时代码随机化防御代码复用攻击】 代码复用攻击是一种高级的恶意攻击手段,它利用了程序中已存在的可执行代码片段(称为gadgets)来构造新的恶意指令序列,绕过传统安全机制。随着攻击技术的发展,代码复用...
在编程领域,代码复用是提高效率和保持代码可维护性的重要原则。然而,不当的代码复用可能会引入问题。本文将探讨四种常见的代码复用模式,并分析它们的优缺点。 首先,我们来看“默认模式”的代码复用,即通过父类...
"jsp页面代码复用组件工具:easylayout" 指的是一种基于JavaServer Pages (JSP) 技术的代码复用工具,名为 "easylayout"。这个工具主要目的是为了提高开发效率,通过封装布局和组件,减少开发者在编写JSP页面时重复...
任何编程都提出代码复用,否则话每次开发一个新程序或者写一个新功能都要全新编写的话,那就歇菜了,但是代码复用也是有好要坏,接下来的两篇文章我们将针对代码复用来进行讨论,第一篇文避免篇,指的是要尽量避免...
近年来,代码复用攻击已经成为安全领域的重要研究课题,而内核级代码复用攻击利用内核自身代码绕过传统的防御机制,使得这类攻击更具隐蔽性和危害性。现有的大多数检测方法主要集中在应用层的代码复用攻击,对内核级...
DRY(Don't Repeat ...总的来说,理解并正确应用DRY原则,以及掌握如何提高代码复用性,是提高软件质量、降低维护成本的关键。在实际开发中,我们需要时刻注意识别和消除代码的冗余,使我们的代码更加简洁、高效。
本教程将通过一个具体的示例——HZLoginView,深入讲解如何在Android中创建自定义View并实现代码复用及自定义属性。 首先,理解自定义View的基本步骤: 1. 创建一个新的Java类:通常,我们继承自Android的基础View...
### 软件工程中的代码复用与组件化 #### 第1章 软件工程概述 **软件工程简介** 软件工程是一门结合了计算机科学、管理学等多个领域的交叉学科,其目的是为了有效地管理和开发软件产品。软件工程的核心任务包括...
在本压缩包中,包含的是关于查理复用LED数码管的源代码,适用于那些希望在项目中使用这种高效驱动技术的开发者。 查理复用的基本原理是:假设我们有n个LED和n个GPIO引脚,理论上最多可以控制2^(n-1)个LED,因为不是...
本人十余年JAVA架构设计经验,擅长JAVA高可用、分布式、高并发系统架构设计。有志于做JAVA系统性的技术提升的同学可与我联系,交个朋友哦~ 本人十余年JAVA架构设计经验,擅长JAVA高可用、分布式、高并发系统架构...