程序设计原则

在写方法(函数)的过程中,总结了如下原则:

【问题1】、有些方法,内容都差不多,只是参数的个数不一样。此时,到底是写多个方法呢,还是写一个方法涵盖所有功能(根据传入的标识去执行不同的步骤)。

A、写多个方法,每个方法参数不同

优点:每个方法执行一件事情,过程清晰明了,调用也简单。

缺点:多个方法,有很多代码是冗余的,而且要改起来很麻烦。

B、写一个方法,涵盖所有参数

优点:只需要编写和维护一套代码。

缺点:调用时需要明确指定所有参数。需要做很多判断,性能稍微低一点(可以忽略)。

》》》举例:

改变字符串编码的方法:

按照A原则,可以写两个方法:

changeCode(String orgStr);

changeCode(String orgStr, String charSet);

但是按照B原则,则只需要写一个方法:

changeCode(String orgStr, String charSet);

因为方法二的功能已经包括了方法一的功能。

如上所述,其实二者各有优劣,但是我更倾向于第二种方法。

因为:

对于调用者而言,只有一个方法供选择,而且他必须显式的指定第二个参数。对调用者而言,是透明的。

对于写方法的人而言,注意到,他应该检查参数的合法性,按照A原则,如果调用了第二个方法,但是第二个参数为空,那这个时候怎么办?

应该调用方法1呢,还是说直接报错?那既然反正都要检查这个charSet的参数,那何不制定一个规则:调用第2个方法,如果charSet为空,则执行第1个方法的流程。

总结:通常情况下,优先采用B方案,采用A方案的情景为

1)如果某些参数的方法使用非常频繁,则可以单独提出来,做成一个独立的方法。

2)参数个数相同,但是参数类型不同(但是也可以用模糊类型的参数,在方法内再去判断参数的类型)。

【问题2】、一个方法执行时走到了错误的流程,应该返回一个标识呢,还是throw一个错误?

A、返回一个标识,例如,执行失败,则返回null、-1等。

优点:执行失败时,返回null或者-1,调用者根据返回的标识即可判断执行是否有错。不需要try-catch。

缺点:通常,调用者不会去判断返回的结果是什么,它也不知道返回值代表的标识是什么,所以当返回null、-1时,可能导致后期无法预知的错误。

B、throw一个错误,终止程序。

优点:无需定义错误标识,而且throw错误时,可以给出错误信息。

缺点:调用者,需要用try-catch去捕获错误,比较麻烦。

总结:对于那种公用的方法,还是采用方案B较好,可以约定,一律采用方案B

【问题3】、什么样的错误往外抛,什么样的错误内部处理?还有,错误日志的记录 应该在哪一层做处理(里层还是外层)?

引入自定义 Runtime Exception: ZtyRuntimeException

 和自定义 Checked Exception: MedialException。

前者,自动中断程序运行,默认情况下将堆栈信息打印到控制台,通过重载Thread.setDefaultUncaughtExceptionHandler方法,可以改变其策略,将运行时异常处理后再写入日志中。

    后者必须在外层程序中捕捉进行处理。最佳的流程是:如果不需要后续处理,则直接抛出Runtime Exception,否则通过MedialException传递Exception到最外层,由最外层将错误代码和错误信息展示或者传给第三方系统。

     日志的处理一定要定位准确,所以通常情况下,哪里出错,就在哪里记录日志,不要在外层写日志,外层只负责处理错误后的程序逻辑,不负责写日志的工作。

一个例子:

D程序调用C程序,C程序调用B程序,B程序调用A程序,现在A程序出错了。

情景一:

       D程序需要得到执行是否正确的回调信息,然后做相应处理。

那么,错误处理应该为:A抛出MedialException(errorCode, errorMsg),B、C和A一样,D捕获MedialException异常,将errorCode和errorMsg转发到视图层或者调用方。

情景二:

      D、C、B程序不需要回调信息,执行不成功只需要终止就行了。无论在哪里终止都可以,框架会捕获一个全局异常信息,然后显示全局错误页面。

情景三:

      D、C、B、A流程环环相扣,联系紧密,但是都没有需要显示捕获的异常,正常情况下,是不会出错的。只有当出现未捕获的RuntimeException时,才会导致程序异常终止,

这种终止是未曾预料到的,可能导致严重后果。

情景二分析:直接抛出自定义的运行时异常ZtyRuntimeException,全局捕获到时,打印错误信息就可以了。

情景三分析:首先我们应该分析,哪些步骤是关键性且不允许出现异常的(例如一个操作具有“要么全部成功、要么全部不成功”的特点时),需要尽量预料哪些地方容易出错,进而捕获错误。

其次,无论我们怎么努力,都有一些无法预料的错误出现,那么这个时候,我们只能考虑是否要将这些错误信息记录下来?如果要记录下来,一种方式,是通过全局的错误处理,另一种是针对性

的处理(例如:全局处理是打印堆栈信息到控制台,但是如果某个功能出错时你想要记录日志)。针对性处理,可以在入口处捕获整个方法,然后做专门处理。

结合情景一、二、三,一个功能最齐全的处理流程是这样的:

A抛出MedialException错误信息给B,同时A调用了两个工具类,可能出现自定义的运行时异常ZtyRuntimeException和未捕获的运行时异常RuntimeException(及其子类)

B抛出MedialException错误信息给C,

C抛出MedialException错误信息给D,D收到MedialException异常后,将errorCode和errorMsg发送到页面上。

由于D过程十分重要,不允许出现未知异常,但是未知异常是无法避免的,为了捕获D在执行过程中出现未知异常,我们在D的整个方法上,加上了如下代码:

try{
   // ..... 整个D的方法
  }catch (TreRuntimeException e) {
    LOG.error( e.getMessage() );
  }catch (RuntimeException e) {
    LOG.error( e );
  }

这样,即使D出现了未知错误,也可以记录日志,便于我们分析。其中对TreRuntimeException错误进行了区别对待,因为TreRuntimeException的错误信息已经经过了加工,

它的errorMsg里面自带了一手堆栈信息,故不需要像未知RuntimeException那样记录堆栈信息了。

总结:对于那种公用的方法,还是采用方案B较好,可以约定,一律采用方案B

原文地址:https://www.cnblogs.com/zollty/p/3284951.html