基本功

最近没有去用太多时间研究Haskell,而是又把很多精力放回到已经工作了将近10年的Java了。原因很简单,这些日子和公司的一位老手合作,才豁然发现其实自己编程的基本功很差。对程序员来说,语言的选择只是问题的一个方面,更重要的是他如何对待自己写出的每一行代码,境界的差别全在其中。就拿我这一两天学到的为例。

本文原发在巴别诺瓦,把上篇BLOG没有细说的设计说清楚了。

最近没有去用太多时间研究Haskell,而是又把很多精力放回到已经工作了将近10年的Java了。原因很简单,这些日子和公司的一位老手合作,才豁然发现其实自己编程的基本功很差。

对程序员来说,语言的选择只是问题的一个方面,更重要的是他如何对待自己写出的每一行代码,境界的差别全在其中。就拿我这一两天学到的为例。

public static String format(Object[] arguments, String pattern) {
return java.text.MessageFormat.format(pattern, arguments);
}

public static void test() {
format(new Object[]{"a", "b"}, "{0}_{1}");
}

比如,上面这段普通不过的代码如何改进?我看到了下面的代码才明白自己没有真正理解变参函数的长处:

public static String format(String pattern, Object... arguments) {
return java.text.MessageFormat.format(pattern, arguments);
}

public static void test() {
format("{0}_{1}", "a", "b");
}

这只是一个小的细节。下面再举一个设计的例子,关于一个代码生成器:

需求很简单,输入一个格式类似 “${a.b.c}” 的字串,把它按照一定的业务规则,输出为另外一段代码

上面描述的过程在业务类里面大量重复出现,一个可以设想的解决办法是把重复的代码提升到父类里面。

public String generate(Context ctx) {
Reference ref = resolveReference(m_ref);

String clazz = ctx.getClass(ref.getFirstPart());
String variable = getVariable(ref, "url");
String scriptlet = getScriptlet (ref, clazz, "url");

ctx.setAttribute(variable, scriptlet);
return "${" + variable + "}";
}

然而因为父类导致抽象层次的增加,很多时候这种做法并不一定导致最好的解决方案,反而让代码变得难懂。有时候引入一个恰当的记法和工具类,可以使得代码变得异常的清晰。

public String generate(Context ctx) {

Object[] parts = FormatHelper.parse(m_ref, "$'{'{0}.{1}.{2}'}'");

String clazz = ctx.getClass((String) parts[0]);
String variable = FormatHelper.format("_url_{0}_{1}_{2}", parts);
String scriptlet = FormatHelper.format( "{0}.url({3}.{1}.{2})", parts[0], parts[1], parts[2], clazz);

ctx.setAttribute(variable, scriptlet);
return "${" + variable + "}";
}

这样是不是清晰了很多呢?更多的好处还在于工具类没有破坏业务类的完整,对业务逻辑的控制权始终掌握在业务类里面,提高了代码的内聚性。

这位老手的话不多,但他评审代码的意见都很到位,让我心悦诚服。

更多想说的是,热爱编程的程序员应该要精益求精,追求代码的完美。只有多磨练,才能出真功夫。

5 thoughts on “基本功

  1. 第一个例子只是展现了可变参数的使用

    第二个例子,没有类的上下文,让人很难理解改变后的好处

  2. 或许还应该再加一条,那就是多多阅读世界上最出色的程序员写的代码 😉

    变长参数在 Java 里的笨重的记法,似乎已经抵销掉它原本带来的好处了,想想 C 中的 printf 在调用时是多么的优雅:

    printf("Inserted %d out of %d.
    ", i, count);

    JavaScript/Perl 里当然就更容易了,所有函数默认都是变长的,呵呵,不仅调用方便,定义也方便 😉

    Haskell 里没有类似的变长参数,毕竟在那里变长参数的调用记法已挪为他用--服务于 curry 了 :))

  3. Hi mingli,

    现在 Babelnova 发表文章支持 publishing options,如果你希望自己发表的某些文章站外全文可见(比如你需要索引,或者和朋友在站外讨论),可以uncheck 那个"非成员用户限制访问"的选项,具体参见用户手册。

    HTH.

发表评论

电子邮件地址不会被公开。 必填项已用*标注