`
zhang_xzhi_xjtu
  • 浏览: 536922 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

实践中的重构01_一段代码的细调

阅读更多
重构的概念已经为广大的程序员所熟悉。但是还是有很多细节可以注意。
    public static String getHiddenEmail(String email, int prefix, int suffix) {
        // 仅对包含@的email账户进行处理
        if (StringUtil.isBlank(email) || !StringUtil.contains(email, "@")) {
            return email;
        }

        int length = email.length();

        if (length < DEFAULT_TOTAL) {
            return email;
        }
        // @所在位置
        int splitPos = StringUtil.lastIndexOf(email, '@');
        // @前的字符段
        String preEmail = StringUtil.substring(email, 0, splitPos);
        if (StringUtil.isBlank(preEmail)) {
            return email;
        }
        // @后的字符段,包含@
        String latEmail = StringUtil.substring(email, splitPos, length);
        if (StringUtil.isBlank(latEmail)) {
            return email;
        }
        if (preEmail.length() > 17)
            preEmail = StringUtil.abbreviate(preEmail, prefix);

        if (latEmail.length() > 13)
            latEmail = StringUtil.abbreviate(latEmail, suffix);

        return preEmail.concat(latEmail);
    }

以上的code在我看来,有以下几个缺点。
1 方法名和实际的方法体不匹配。
2 魔数
3 if (StringUtil.isBlank(latEmail)) 永远返回false,因为当程序执行到这里,latEmail至少包括一个字符@。
4 方法中的代码的内聚性不够。主要是对preEmail和latEmail的处理分开了。
5 拼写错误,应该为lastEmail而误拼为latEmail

清洗代码后如下
private static String getAbbreviatedEmail(String email, int prefix, int suffix) {

        if (StringUtil.isBlank(email)) {
            return email;
        }

        if (email.length() <= DEFAULT_TOTAL) {
            return email;
        }

        // @所在位置
        int splitPos = StringUtil.lastIndexOf(email, '@');
        if (splitPos == -1 || splitPos == 0|| splitPos == email.length() - 1) {
            return email;
        }

        // @前的字符段
        String preEmail = StringUtil.substring(email, 0, splitPos);
        if (preEmail.length() > DEFAULT_PREFIX_LENGTH) {
            preEmail = StringUtil.abbreviate(preEmail, prefix);
        }

        // @后的字符段,包含@
        String lastEmail = StringUtil.substring(email, splitPos, email.length());
        if (lastEmail.length() > DEFAULT_SUFFIX_LENGTH) {
            lastEmail = StringUtil.abbreviate(lastEmail , suffix);
        }

        return preEmail+lastEmail ;
    }


其实我个人最喜欢的风格是简单的方法的guard condition不用大括号{},这样代码变为

private static String getAbbreviatedEmail(String email, int prefix, int suffix) {

        if (StringUtil.isBlank(email)) 
            return email;

        if (email.length() <= DEFAULT_TOTAL) 
            return email;

        // @所在位置
        int splitPos = StringUtil.lastIndexOf(email, '@');
        if (splitPos == -1 || splitPos == 0|| splitPos == email.length() - 1) 
            return email;

        // @前的字符段
        String preEmail = StringUtil.substring(email, 0, splitPos);
        if (preEmail.length() > DEFAULT_PREFIX_LENGTH) {
            preEmail = StringUtil.abbreviate(preEmail, prefix);
        }

        // @后的字符段,包含@
        String lastEmail = StringUtil.substring(email, splitPos, email.length());
        if (lastEmail.length() > DEFAULT_SUFFIX_LENGTH) {
            lastEmail = StringUtil.abbreviate(lastEmail , suffix);
        }

        return preEmail+lastEmail ;
    }


谢谢论坛上朋友的讨论,preEmail+latEmail这个地方用+号比用concat方法好。
分享到:
评论
21 楼 Ben.Sin 2010-08-04  
<div class="quote_title">zhang_xzhi_xjtu 写道</div>
<div class="quote_div">
<br><br>清洗代码后如下<br><pre name="code" class="java">private static String getAbbreviatedEmail(String email, int prefix, int suffix) {

        if (StringUtil.isBlank(email)) {
            return email;
        }

        if (email.length() &lt;= DEFAULT_TOTAL) {
            return email;
        }

        // @所在位置
        int splitPos = StringUtil.lastIndexOf(email, '@');
        if (splitPos == -1 || splitPos == 0) {
            return email;
        }

        // @前的字符段
        String preEmail = StringUtil.substring(email, 0, splitPos);
        if (preEmail.length() &gt; DEFAULT_PREFIX_LENGTH) {
            preEmail = StringUtil.abbreviate(preEmail, prefix);
        }

        // @后的字符段,包含@
        String lastEmail = StringUtil.substring(email, splitPos, email.length());
        if (lastEmail.length() &gt; DEFAULT_SUFFIX_LENGTH) {
            lastEmail = StringUtil.abbreviate(latEmail, suffix);
        }

        return preEmail.concat(latEmail);
    }</pre>
<br><br><br>
</div>
<p> </p>
<p>是少了一点重构的影子。。</p>
<p>只是更改了一下名字是不够的,要将相似的代码提取独立成函数,例如:</p>
<p> </p>
<pre name="code" class="java">private static String getAbbreviatedEmail(String email, int prefix, int suffix) {

if (StringUtils.isBlank(email)) {
return email;
}

if (email.length() &lt;= DEFAULT_TOTAL) {
return email;
}

// @所在位置
int splitPos = StringUtils.lastIndexOf(email, '@');
if (splitPos == -1 || splitPos == 0) {
return email;
}

// @前的字符段
String preEmail = abbreviate(email, 0, splitPos, prefix);

// @后的字符段,包含@
String lastEmail = abbreviate(email, splitPos, email.length(), suffix);

return preEmail.concat(lastEmail);
}

private static String abbreviate(String src, int start, int end, int maxLength){
String result = StringUtils.substring(src, start, end);
if (end - start &gt; maxLength) {
result = StringUtils.abbreviate(result, maxLength);
}
return result;
}</pre>
<p> </p>
<p>重构一书提倡的是简化代码结构,而不优先考虑性能问题,所以,还可以</p>
<p> </p>
<pre name="code" class="java">private static String getAbbreviatedEmail(String email, int prefix, int suffix) {

if (StringUtils.isBlank(email)) {
return email;
}

if (email.length() &lt;= DEFAULT_TOTAL) {
return email;
}

// @所在位置
int splitPos = StringUtils.lastIndexOf(email, '@');
if (splitPos == -1 || splitPos == 0) {
return email;
}

// @前的字符段
String preEmail = StringUtils.abbreviate(email.substring(0, splitPos), prefix);

// @后的字符段,包含@
String lastEmail = StringUtils.abbreviate(email.substring(splitPos), suffix);

return preEmail.concat(lastEmail);
}</pre>
 
20 楼 zhang_xzhi_xjtu 2010-08-04  
抛出异常的爱 写道
对于2,4,5
还有传入的后两个值
三个default值

你可以描述一下
他们所表示的目的
不是实现方式

你就发现设计这几个数值的人是程序员而不是需求.
//一针见血

public static String abbreviate(String str, int maxWidth)
max 到底是default 还是传入的数值.
非常的混乱.
名子也很混乱.
读代码只能明白期待值
而不能明白目的就不太可能成为好代码 .
//这个max是传入的。如果是default就不会传了。

19 楼 zhang_xzhi_xjtu 2010-08-04  
flyingpig4 写道
我理解的好的代码应该只有一个出口,所以稍微改了一下楼主的代码,欢迎大家拍砖
private static String getAbbreviatedEmail(String email, int prefix, int suffix) { 

  String reemail;
  if (StringUtil.isBlank(email)||email.length() <= DEFAULT_TOTAL) { 
           reemail=email;
   } 
  else
{
        // @所在位置 
       int splitPos = StringUtil.lastIndexOf(email, '@'); 
       if (splitPos == -1 || splitPos == 0) { 
            reemail=email;
       } 
else{

// @前的字符段 
   String preEmail = StringUtil.substring(email, 0, splitPos); 
if (preEmail.length() > DEFAULT_PREFIX_LENGTH) { 
preEmail=StringUtil.abbreviate(preEmail, prefix)

   // @后的字符段,包含@ 
   String lastEmail = StringUtil.substring(email, splitPos, email.length()); 
   if (lastEmail.length() > DEFAULT_SUFFIX_LENGTH) { 
lastEmail=StringUtil.abbreviate(latEmail, suffix); 

  
   reemail=preEmail.contact(lastEmail);
   }
}
return reemail;


单入口单出口是一个好的实践 但是并不适应所有的情况。
你改动的这个看着是有点晕晕的。
18 楼 herryhaixiao 2010-08-04  
flyingpig4 写道
我理解的好的代码应该只有一个出口,所以稍微改了一下楼主的代码,欢迎大家拍砖
private static String getAbbreviatedEmail(String email, int prefix, int suffix) { 

  String reemail;
  if (StringUtil.isBlank(email)||email.length() <= DEFAULT_TOTAL) { 
           reemail=email;
   } 
  else
{
        // @所在位置 
       int splitPos = StringUtil.lastIndexOf(email, '@'); 
       if (splitPos == -1 || splitPos == 0) { 
            reemail=email;
       } 
else{

// @前的字符段 
   String preEmail = StringUtil.substring(email, 0, splitPos); 
if (preEmail.length() > DEFAULT_PREFIX_LENGTH) { 
preEmail=StringUtil.abbreviate(preEmail, prefix)

   // @后的字符段,包含@ 
   String lastEmail = StringUtil.substring(email, splitPos, email.length()); 
   if (lastEmail.length() > DEFAULT_SUFFIX_LENGTH) { 
lastEmail=StringUtil.abbreviate(latEmail, suffix); 

  
   reemail=preEmail.contact(lastEmail);
   }
}
return reemail;

这个处理根本就不是重构了,反而使简单的事情变的复杂了,太多的if条件判断,而且把这段代码给别人看,别人也会很晕
17 楼 抛出异常的爱 2010-08-04  
对于2,4,5
还有传入的后两个值
三个default值

你可以描述一下
他们所表示的目的
不是实现方式

你就发现设计这几个数值的人是程序员而不是需求.

public static String abbreviate(String str, int maxWidth)
max 到底是default 还是传入的数值.
非常的混乱.
名子也很混乱.
读代码只能明白期待值
而不能明白目的就不太可能成为好代码 .
16 楼 vishare 2010-08-04  
适合初学者,我喜欢.
15 楼 daquan198163 2010-08-04  
flyingpig4 写道
我理解的好的代码应该只有一个出口,所以稍微改了一下楼主的代码,欢迎大家拍砖
private static String getAbbreviatedEmail(String email, int prefix, int suffix) { 

  String reemail;
  if (StringUtil.isBlank(email)||email.length() <= DEFAULT_TOTAL) { 
           reemail=email;
   } 
  else
{
        // @所在位置 
       int splitPos = StringUtil.lastIndexOf(email, '@'); 
       if (splitPos == -1 || splitPos == 0) { 
            reemail=email;
       } 
else{

// @前的字符段 
   String preEmail = StringUtil.substring(email, 0, splitPos); 
if (preEmail.length() > DEFAULT_PREFIX_LENGTH) { 
preEmail=StringUtil.abbreviate(preEmail, prefix)

   // @后的字符段,包含@ 
   String lastEmail = StringUtil.substring(email, splitPos, email.length()); 
   if (lastEmail.length() > DEFAULT_SUFFIX_LENGTH) { 
lastEmail=StringUtil.abbreviate(latEmail, suffix); 

  
   reemail=preEmail.contact(lastEmail);
   }
}
return reemail;

不好,如果用人脑执行这段代码,需要多费不少精力。
14 楼 beneo 2010-08-04  
一直不明白,魔数有那么差么?
13 楼 chris_zley 2010-08-04  
正则还是比较好理解的,而且楼主不过是验了一下@和前后缀长度而已,一般不可能弄出很复杂的正则表达式

重构后感觉条理清晰多了,不过我觉得大部分人写出来的应该都是这一版,而很少出现第一种情况啊
12 楼 flyingpig4 2010-08-04  
我理解的好的代码应该只有一个出口,所以稍微改了一下楼主的代码,欢迎大家拍砖
private static String getAbbreviatedEmail(String email, int prefix, int suffix) { 

  String reemail;
  if (StringUtil.isBlank(email)||email.length() <= DEFAULT_TOTAL) { 
           reemail=email;
   } 
  else
{
        // @所在位置 
       int splitPos = StringUtil.lastIndexOf(email, '@'); 
       if (splitPos == -1 || splitPos == 0) { 
            reemail=email;
       } 
else{

// @前的字符段 
   String preEmail = StringUtil.substring(email, 0, splitPos); 
if (preEmail.length() > DEFAULT_PREFIX_LENGTH) { 
preEmail=StringUtil.abbreviate(preEmail, prefix)

   // @后的字符段,包含@ 
   String lastEmail = StringUtil.substring(email, splitPos, email.length()); 
   if (lastEmail.length() > DEFAULT_SUFFIX_LENGTH) { 
lastEmail=StringUtil.abbreviate(latEmail, suffix); 

  
   reemail=preEmail.contact(lastEmail);
   }
}
return reemail;
11 楼 zhang_xzhi_xjtu 2010-08-03  
iaimstar 写道
没感觉重构完之后有什么不同

好冷
10 楼 zhang_xzhi_xjtu 2010-08-03  
抛出异常的爱 写道
zhang_xzhi_xjtu 写道


其实我个人最喜欢的风格是简单的方法的guard condition不用大括号{},这样代码变为

private static String getAbbreviatedEmail(String email, int prefix, int suffix) {

        if (StringUtil.isBlank(email)) //1
            return email;

        if (email.length() <= DEFAULT_TOTAL) //2
            return email;

        // @所在位置
        int splitPos = StringUtil.lastIndexOf(email, '@');
        if (splitPos == -1 || splitPos == 0) //3
            return email;

        // @前的字符段
        String preEmail = StringUtil.substring(email, 0, splitPos);
        if (preEmail.length() > DEFAULT_PREFIX_LENGTH) {//4
            preEmail = StringUtil.abbreviate(preEmail, prefix);
        }

        // @后的字符段,包含@
        String lastEmail = StringUtil.substring(email, splitPos, email.length());
        if (lastEmail.length() > DEFAULT_SUFFIX_LENGTH) {//5
            lastEmail = StringUtil.abbreviate(latEmail, suffix);
        }

        return preEmail.concat(latEmail);
    }


正则式可以干掉1 ,3 ,多个@ , @在开头 状况
//一般的程序员对正则并不熟悉,用正则的话程序的清晰性下降。
//还有一个原因是我不知道有没有精确的email格式定义。

2 与 4,5 逻辑重叠
如果不是重构.
可以问一下美工到底是要什么效果
去掉其中的一些逻辑.
//逻辑没有重复啊,2是判断总长度的,4,5是判断前缀和后缀的,对于总长度不超的,即使其前缀或后缀超出也是不处理的。


preEmail变换....与lastEmail变换最好不要把自己变更
//一般是不建议给变量重新赋值,但是这个一般是对传入参数而言,方法体内的变量意义保持清晰的时候我认为重新赋值是没有问题的。而且String是不变类型,也没有什么诡异的副作用。

还有就是返回值 return preEmail+latEmail;
就可以了看的明白更重要一些.
//同意

看一下能否用上.
StringBuilder buffer = StringBuilder();
String[] emailarry = StringUtil.split(email,"@");
int[] keys = {DEFAULT_PREFIX_LENGTH,DEFAULT_SUFFIX_LENGTH};
for(int i = 0 ; i < emailarry.length ; i++){
   ...............
}

//这个怎么用,请明示。谢谢。



9 楼 iaimstar 2010-08-03  
没感觉重构完之后有什么不同
8 楼 抛出异常的爱 2010-08-03  
zhang_xzhi_xjtu 写道


其实我个人最喜欢的风格是简单的方法的guard condition不用大括号{},这样代码变为

private static String getAbbreviatedEmail(String email, int prefix, int suffix) {

        if (StringUtil.isBlank(email)) //1
            return email;

        if (email.length() <= DEFAULT_TOTAL) //2
            return email;

        // @所在位置
        int splitPos = StringUtil.lastIndexOf(email, '@');
        if (splitPos == -1 || splitPos == 0) //3
            return email;

        // @前的字符段
        String preEmail = StringUtil.substring(email, 0, splitPos);
        if (preEmail.length() > DEFAULT_PREFIX_LENGTH) {//4
            preEmail = StringUtil.abbreviate(preEmail, prefix);
        }

        // @后的字符段,包含@
        String lastEmail = StringUtil.substring(email, splitPos, email.length());
        if (lastEmail.length() > DEFAULT_SUFFIX_LENGTH) {//5
            lastEmail = StringUtil.abbreviate(latEmail, suffix);
        }

        return preEmail.concat(latEmail);
    }


正则式可以干掉1 ,3 ,多个@ , @在开头 状况 
2 与 4,5 逻辑重叠
如果不是重构.
可以问一下美工到底是要什么效果
去掉其中的一些逻辑.

preEmail变换....与lastEmail变换最好不要把自己变更

还有就是返回值 return preEmail+latEmail;
就可以了看的明白更重要一些.

看一下能否用上.
StringBuilder buffer = StringBuilder();
String[] emailarry = StringUtil.split(email,"@");
int[] keys = {DEFAULT_PREFIX_LENGTH,DEFAULT_SUFFIX_LENGTH};
for(int i = 0 ; i < emailarry.length ; i++){
   ...............
}

7 楼 jiangduxi 2010-08-03  
liyun_1981 写道
还可以再精简一下。
if (splitPos == -1 || splitPos == 0) {   

改为
if (splitPos < 1) {   


这样改将会出现问题。 splitPos == -1 || aplitPos == 0 不能用splitpos <1来表示。你改变它的作用范围。
6 楼 zhang_xzhi_xjtu 2010-08-03  
liyun_1981 写道
还可以再精简一下。
if (splitPos == -1 || splitPos == 0) {   

改为
if (splitPos < 1) {   


这样代码行数是少了 但是代码的含义变得不是很清晰
5 楼 liyun_1981 2010-08-03  
还可以再精简一下。
if (splitPos == -1 || splitPos == 0) {   

改为
if (splitPos < 1) {   
4 楼 zhang_xzhi_xjtu 2010-08-03  
snow8261 写道
可否举个更加复杂的重构例子

这个是个好想法 但是得慢慢来 复杂的你可以看我的blog的CodeLineCounter,那个是一步一步进化而来。
而且最近又在重构。
这个系列主要记录一些平时遇到的小问题的重构,一般是维护其他人的代码的时候的一些小例子。
3 楼 snow8261 2010-08-03  
可否举个更加复杂的重构例子
2 楼 zhang_xzhi_xjtu 2010-08-02  
恩 重构的书不错 不过更应该看重的是重构的精神 然后在以后的代码里面 一遍一遍的搞 直到自己可以满意

相关推荐

    重构_改善既有代码的设计 Java

    《重构:改善既有代码的设计》是一本在IT领域广受推崇的经典著作,专注于软件开发中的重构实践,尤其针对Java编程语言。重构是软件开发过程中的一个重要环节,它旨在提升代码的可读性、可维护性和整体质量,而不会...

    重构_改善既有代码的设计

    《重构:改善既有代码的设计》这本书为软件工程师提供了一套系统的方法论,帮助他们在实践中有效地改善既有代码的质量。通过对代码进行持续不断的优化,不仅能够提高软件产品的整体质量,还能提升开发团队的工作效率...

    重构_改善既有代码的设计.pdf

    这是一种常见的重构技巧,涉及将一段代码提取到一个单独的方法中,并替换原始代码中的相应部分。这种方法可以提高代码的可读性和可维护性。 **移动功能(Move Function)**: 当某个类中的某些功能更适合另一个类时...

    重构_改善既有代码的设计高清版.pdf

    2. **提取方法**:将一段代码封装成一个独立的方法,使其更易于复用和测试。 3. **内联方法**:如果一个方法仅在一处调用,并且其功能可以很容易地融入调用者,则可以考虑将其内联。 4. **移动功能**:将一个方法或...

    重构-改善既有代码的设计

    重构是软件开发过程中一个至关重要的环节,它旨在不改变代码外在行为的前提下,改进代码结构,使之更易理解和修改。此书深入浅出地介绍了重构的概念、原则和实践方法,对于任何Java开发者来说,都是提升编码技艺的...

    重构_改善既有代码的设计.zip

    《重构:改善既有代码的设计》是一本在IT行业中极具影响力的著作,由马丁·福勒(Martin Fowler)撰写。这本书深入探讨了重构这一编程实践,旨在提高软件的质量、可读性和可维护性,同时保持现有功能的稳定。通过一...

    重构pdf_chonggou

    首先,提取函数是一种常见的重构手法,它将一段复杂的代码块封装成独立的函数,使代码更易于理解和测试。这样做可以使代码逻辑更清晰,同时也便于复用和修改。 其次,提取类是为了更好地实现面向对象编程,将一组...

    重构改善既有代码的设计PPT课件

    通过重构,设计人员可以避免过度设计,只需先找到合理解决方案,后续实践中再根据实际情况优化。 识别代码的“坏味道”是重构的重要步骤。例如,重复代码是常见的问题,可以通过提炼函数或应用设计模式如Template ...

Global site tag (gtag.js) - Google Analytics