首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

相关代码复用

2012-12-18 
有关代码复用}这个接口暴露了两层抽象1,2是Container操作,3,4,5是List操作.实际上我们只需要1,2.这里不应

有关代码复用

}

这个接口暴露了两层抽象1,2是Container操作,3,4,5是List操作.实际上我们只需要1,2.这里不应该用继承而应该使用组合.这样做会暴露内部的实现机制,造成客户调用的混乱,

public class EmpolyeeContains{

}

1,2的操作通过3的数据结构实现,但是接口本身不暴露内部的实现机制.暴露的内部细节越少越有利于修改.

2).提供成对(组)的服务.

3).尽可能让接口可编程,而不是表达语义.

暴露的接口应该仅仅通过编译器就能限制其使用方法,例如接口限定方法的参数类型,个数等等编译器可检查的错误.如果接口中有这样的方法step1(),step2(),隐含的表达step1必须在step2之前调用否则会出错,这种语义性的行为是编译器无法检查的.也就是说调用者有可能会调用错误.应该尽量避免这种接口设计,至少要通过注释文档说明这种语义.

public boolean validateUser(Useruser){

??? session.init();

??? if(user.getPassword().equals(password)){

??? ??? return true ;

??? }else{

??? ??? return false ;

??? }

}

30秒原则(任何方法如果在30秒内不能阅读理解,就应当做进一步拆分).

private HttpUriRequestbuildHttpPost() {

??? Stringuri = uriPattern.replaceAll("\\?.*", "");//1

??? logger.info("POST请求:\n{}", uri);//2

??? HttpPostreq = new HttpPost(uri);//3

??? HttpEntityentity = buildHttpEntity();//4

??? req.setEntity(entity);//5

??? returnreq;

}

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).这样就一目了然了.

输出参数是不建议使用的,应该尽量使用返回值做为输出结果.

变量和方法名称应当有意义,做到代码本身就是自解释的.

推荐书籍<CleanCode>代码整洁之道.代码大全,敏捷软件开发

继承是OO中很方便的复用代码的方式,虽然Java只支持单继承,降低了继承的复杂度,但当继承层次增加,代码的可读性就会下降,内部细节也越复杂子类对父类的依赖和耦合也比较严重.特别是子类使用父类的保护成员和字段的时候,这样的类在阅读代码的时候是很晦涩的.

对象组合技术同样可以实现继承带来的功能(虽然有时要多些一些代码,但是可以让程序结构更简单灵活)

观察如下代码.

abstract classAbstractExampleDocument
{
??? // 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.

可见优先使用对象组合,和面向接口编程可以很好的利用依赖注入实现代码的解耦提高代码的可维护性和可扩展性.

单一职权和开放封闭原则.

该原则要求代码对扩展是开放的,对修改是封闭的.最佳状态是一个类或者方法,只有一个引起变化的理由.当然要做到这一点首先就是要符合单一职权原则(只做一件事).符合单一职权原则才可以保证只要在要做的那件事的需求有变化的时候才会修改代码.否则只需要扩展代码.实现开放封闭的方式有很多,例如前面的对象组合技术,还有很多有关的设计模式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);

?

这样明显逻辑清楚而且很容易修改,代码量也下降了.也很容易进行方法拆分.

?

做到上述的代码就是可复用的好代码吗?未必,作为一个开发人员编写好代码是贯彻始终的,所有的实践均来源于自己和他人的经验总结,到底如何才能写出好的可复用的代码每个人的标准也不完全一致.在此只是提及了一些我认为是大多数人公认的原则和实践.

参考资料,代码整洁之道,代码大全,敏捷软件开发.

热点排行