一次注释必要性的体验

TDD · asj · 于 发布 · 最后由 hkliya回复 · 1500 次阅读
377

注释还是不注释,这是个问题

关于注释,一直都存在一些争议。我记得早年重型软件工程方法论的年代,有一种看法:注释的多少体现一个程序员的职业素养。甚至有些公司有注释与代码比例的考核目标。
后来大家似乎觉得单纯的增加注释量并不能真正提高代码的可维护性,所以又有一种看法:需要注释体现出代码可读性有问题,这时应该修改代码而不是增加注释。甚至有人半开玩笑的说:真正的程序员从来不写注释。
比如有人在Quora上问程序员应该避免哪些坏习惯,有个答案整体说的不错:
1. 糟糕的命名规范
2. 不抽取方法
3. 没有注释
4. 不用内建库
5. 缩进混乱
6. 空格使用混乱
结果马上就被吐槽第三条。

这里还有一个探讨什么才是好的注释的问题,这个国产注释光荣上榜。
image

就我个人而言,是倾向于尽量少些注释的。虽然原则上来说应该在需要说明Why的时候使用注释,不过似乎没怎么遇到过。

举个栗子

前两天做了一道题目,一个三角形被若干条线段分割,求最终形成了多少个三角形。
结果发现这是个极佳的例子,让我体验到了注释在某些情况下的不可或缺
实现过程见 http://cyber-dojo.org/kata/edit/98E4C6CC89?avatar=rhino

测试

import java.util.List;
import java.util.Arrays;

import org.junit.*;
import static org.junit.Assert.*;

public class TriangleCounterTest {
    Pointer p1 = new Pointer();
    Pointer p2 = new Pointer();
    Pointer p3 = new Pointer();
    Pointer p4 = new Pointer();
    Pointer p5 = new Pointer();
    Pointer p6 = new Pointer();
    Pointer p7 = new Pointer();

    private List<Pointer> line(Pointer... points) {
        return Arrays.asList(points);
    }

    @Test
    public void no_inputs_no_triangle() {
        assertEquals(0, TriangleCounter.count());
    }

    @Test
    public void get_1_triangle_from_3_lines() {
        assertEquals(1, TriangleCounter.count(
            line(p1, p2), 
            line(p1, p3), 
            line(p2, p3)
        ));

        assertEquals(1, TriangleCounter.count(
            line(p1, p3), 
            line(p1, p2), 
            line(p2, p3)
        ));
    }


    /**
        .
       / \
      /___\
     /     \
    /_______\
    **/
    @Test
    public void get_2_triangle_from_4_lines() {
        assertEquals(2, TriangleCounter.count(
            line(p1, p4, p2),
            line(p1, p5, p3),
            line(p2, p3),
            line(p4, p5)
        )); 

        assertEquals(2, TriangleCounter.count(
            line(p1, p4, p2),
            line(p2, p3),
            line(p1, p5, p3),
            line(p4, p5)
        )); 

        assertEquals(2, TriangleCounter.count(
            line(p2, p3),
            line(p4, p5),
            line(p1, p4, p2),
            line(p1, p5, p3)
        )); 
   }


    /**
    ._______.
    |       |
    |       |
    |_______|
    **/

    @Test
    public void get_0_triangle_from_4_lines() {
        assertEquals(0, TriangleCounter.count(
            line(p1, p2),
            line(p1, p3),
            line(p2, p4),
            line(p3, p4)
        )); 

        assertEquals(0, TriangleCounter.count(
            line(p1, p2),
            line(p1, p3),
            line(p4, p3),
            line(p2, p4)
        )); 

        assertEquals(0, TriangleCounter.count(
            line(p1, p2),
            line(p3, p4),
            line(p1, p3),
            line(p2, p4)
        )); 
    }

    /**
    ._______.
    |\ _____|
    | |     |
    |_|_____|
    **/
    @Test
    public void get_0_triangle_from_3lines_join_1_point() {
        assertEquals(0, TriangleCounter.count(
            line(p1, p2),
            line(p1, p3),
            line(p1, p5),
            line(p2, p6, p4),
            line(p3, p7, p4),
            line(p5, p6),
            line(p5, p7)
        )); 
    }

    /**
        .
       /|\
      /_|_\
     /  | /\
    /___|/__\
    **/    
    @Test
    public void a_complexer_test() {
        assertEquals(9, TriangleCounter.count(
            line(p1, p5, p2),
            line(p1, p6, p3),
            line(p1, p4, p7),
            line(p2, p7, p3),
            line(p5, p4, p6),
            line(p6, p7)
        )); 
    }
}

实现代码

算法是比较简单的暴力穷举,3层循环套2个if还是蛮丑的,哪天试试用函数式改善一下。

import java.util.List;

public class TriangleCounter {
    @SafeVarargs
    public static int count(List<Pointer>... lines) {
        int result = 0;

        for (int l1 = 0; l1 < lines.length; l1++) {
            for (int l2 = l1+1; l2 < lines.length; l2++) {
                Pointer p1 = crossAt(lines[l1], lines[l2]);
                if (p1 != null) {
                    for (int l3 = l2+1; l3 < lines.length; l3++) {  
                        Pointer p2 = crossAt(lines[l2], lines[l3]);
                        Pointer p3 = crossAt(lines[l1], lines[l3]);
                        if (p2 != null && p2 != p1 &&
                            p3 != null && p3 != p1
                           ) {
                            result += 1;
                        }
                    }
                }
            }
        }
        return result;
    }

    private static Pointer crossAt(List<Pointer> line1, List<Pointer> line2) {
        for (Pointer p : line2) {
            if (line1.contains(p)) {
                return p;
            }
        }
        return null;
    }
}

「软件匠艺社区」旨在传播匠艺精神,通过分享好的「工作方式」和「习惯」以帮助程序员更加快乐高效地编程。
本帖已被设为精华帖!
共收到 1 条回复
1
hkliya · #1 ·

用注释来画图,也是绝了。

需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。