欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2、函数参数列表

程序员文章站 2022-05-29 22:05:34
...

最理想的参数数量是零(零参数函数),其次是一(单参数函数),再次是二(双参数函数),应尽量避免三(三参数函数)。有足够特殊的理由才能用三个以上参数(多参数函数)----所以无论如何也不要这么做。

 

1、一元函数的普遍形式

boolean fielExists("MyFile"); 

上述就是输入一个参数,将其 转换为某一个东西,在输出之。

例如:

InputStream fileOpen("MyFile") 

把 String 类型的文件名转换为InputStream 类型的返回值。

如果函数要对输入参数进行转换操作,转换结果就该体现为返回值。实际上

StringBuffer transform(StringBuffer in) 

要比

void transform(StringBuffer out)

要强。

 

标识参数:true false

向函数传入布尔值简直就是骇人听闻。这样做,方法签名立刻变得复杂起来,大声宣布本函数不止做一件事。如果 表示为true将会这样做,标识为false则会那样做。

比如: 

render(boolean isSuite)

应该一分为二:

renderForSuite();

renderForSingleTest();

 

2、二元函数

有两个参数的函数要比一员函数难懂。例如 writeFile(name) 比 writeFiled(outputStream ,name)好懂。

尽管两种情况下意义都很清楚,但第一个只要扫一眼就明白,更好地表达了其意义。第二个就得暂停以下才明白,除非我们学会忽略第一个参数。

当然,有些时候两个参数正好,例如: Point p = new Point(0,0);将相当合理。笛卡尔点天生拥有两个参数,

使用二元函数要付出代价,你应该尽量利用一些机制将其转换成一元函数。例如:

writeFiled方法写成outputStream的成员之一,从而能这样用: outputStream.writeField(name)。或者 ,也可以把outputStream 写成当前类的成员变量,从而无需再传递。还可以分离出类似FiledWrite 的新类,在其构造器中采用outputStream,并且包含一个write方法。

 

3、三元函数

有三个参数的函数要比二元函数难懂得多。

比如:

assertEquals(message,expected,actual) 

有多少次,你读到message,错以为它既是expected呢,每次看到这里,总会绕半天圈子,最后学会了忽略message参数。

4、参数对象

如果函数需要两个、三个或三个以上参数,就说明其中一些参数应该封装为类了。例如:

Circle makeCircle(double x, double y  , double radius);

Circle makeCircle(Point center ,double radius);

从参数 创建,从而减少参数数量,当一组参数被共同传递,就像上例中x 和 y那样,往往就是该有自己名称的某个概念的一部分。

同时,给函数去个好名字,能较好地解释函数的意图,以及参数的顺序和意图。

 

对于一元函数,函数和参数应当形成一种非常良好的动词/名词对形式,例如,write(name)就相当令人人挺,不管这个"name“是什么,都要被"write"。更好的名称大概是writeFiled(name),它告诉我们,"name" 是一个"filed".

 

assertEquals(message,expected,actual) ';

改成

assertExpectedEqualsActual(expected,actual);

 

5、被隐藏的副作用

比如:

public class  UserValidator{

     .....

   public boolean checkpassword(String usernName,Srting password){

    // 检验密码

   //....

   // session.initialize();

 }

}

副作用在于Session.initialize()的调用。checkPassword 函数,顾名思义,就是用来检查密码的。该名称并未暗示它会初始化该次会话。所以,当某个误信了函数名的调用者想要检查用户有效性,就得冒着抹除现有会话数据的风险。

checkPassword只能在特定时刻调用(换言之,在初始化会话是安全的时候调用的)。如果在不合适的时候调用,会话数据就有可能沉默地丢失。时序性耦合令人迷惑,特备是当它在副作用后面时。如果一定要时序性耦合,就应该在函数名称中说明。在本例中,可以重命名函数为 checkPasswordAndInitializeSession .

 

6、分隔指令与查询

函数 要么做什么事,要不回答什么事,但二者不可兼得。函数应该修改某对象的状态或是返回该对象的有关信息。两者都干常会导致混乱,例如 :

 

public boolean set(String attribute,String value);

 

该函数设置某个指定属性,如果成功就返回true,如果不存在那个属性则返回false,这样就导致了以下语句:

if(set("username","wyy)){}

上述语句可以理解为:

是否之前已设置为wyy吗

或者 

设置username是否成功?

真正的解决方案是: 把 指令与询问分隔开来,防止 混淆的发生:

 if(attributeExists(“username”){
    setAttribute("username","wyy");
}

7、抽离Try/Catch 代码块

Try/Catch 代码块丑陋不堪。他们搞乱了代码结构,把错误梳理与正常流程混为一谈。最好把Try 和 catch 代码块 的主体部分抽离出来,另外形成函数;

public void delete(Page page){

   try{
       deletePageAndALlReferences(page);

   }catch(Exception e){
      logError(e);
   }

}

public void deletePageAndAllReferences(Page page) throws Exception{
   deletePage(page);
   registry.deleteReference(page.name);
   configKeys,deleteKey(page.name.makeKey);
}

private void logError(Execption e){
  logger.log(e.getMessage());
}

函数应该只做一件事,错误处理就是一件事,因此,处理错误的函数不应该做其他事,这意味着如果关键字try在某个函数中存在,它就该是这个函数的第一个单词而且在catch/finally 代码后面不应该有其他内容。

 

8、别重复自己

重复代码是软件中一切邪恶的根源。许多原则与实践原则都是为控制与消除重复而创建,例如在java中,把某些代码几种到基类中,从而避免了冗余。面向切面编程(AOP)也是消除重复的一种策略.

 

9、如何写出好的函数

首先写的冗长而负责,有太多缩进和嵌套循环。有过长的参数列表。名称也是随意取的,也会有重复代码。

然后打磨 这些代码。分解函数、修改名称、消除重复。缩短和重新安置方法。拆散类,同时保持单元测试通过。

最后,遵循上述原则,组装好这些函数。

 

 

 

相关标签: 函数