IT技术博客大学习 共学习 共进步

基于DSL风格的代码重构

淘宝数据平台团队 2010-10-28 07:31:53 浏览 2,861 次

什么样代码是简洁易懂, 这很难有个统一的标准, 因为它很大程度上决定于所在团队的编写风格(往往偏向于核心程序员).

正因如此, 本文仅仅呈现一下DSL的编码风格, 若你喜欢, 不妨在自己的实践中也试试; 不欣赏者, 只当浮云飘过吧

有如下java代码片段:

以下是代码片段:
public class Subscriber {
  private long skip;
  private final Channel channel;

  public Subscriber(final Channel channel, final long skip) {
    this.channel = channel;
    this.skip = skip;
  }

  public void receive(final ChannelBuffer buffer) throws Exception {
    if (buffer == null) {
      channel.write(new DefaultHttpResponse(HttpVersion.HTTP_1_1,
                                            HttpResponseStatus.OK));
      channel.close();
      return;
    }

    if (skip == 0) {
      channel.write(buffer);
      return;
    }

    if (buffer.readableBytes() <= skip) {
      skip = skip - buffer.readableBytes();
      return;
    }

    buffer.skipBytes((int) skip);
    channel.write(buffer);
    skip = 0;
  }
}

代码并不多, 看上去也还算简洁, 只是需要细细琢磨一下才能明白编写者的意图.

为了达到”显意”(代码尽可能直接表露业务含义, 而非执行步骤), 让我们重构一下:

以下是代码片段:
  public void receive(final ChannelBuffer buffer) throws Exception {
    if (isTail(buffer)) {
      sendOkResponseTo(channel);
      return;
    }

    if (skip == 0) {
      send(buffer, channel);
      return;
    }

    if (buffer.readableBytes() <= skip) {
      skip = skip - buffer.readableBytes();
      return;
    }

    buffer.skipBytes((int) skip);
    send(buffer,channel);
    skip = 0;
  }

  static void send(final ChannelBuffer buffer, Channel channel) {
    channel.write(buffer);
  }

  static void sendOkResponseTo(Channel channel) {
    channel.write(new DefaultHttpResponse(HTTP_1_1, OK)); // import static constants
    channel.close();
  }

  static boolean isTail(final ChannelBuffer buffer) {
    return buffer == null;
  }

似乎好了点, 至少能够一看出来的是:

  1. 若buffer到达结尾, 需要向channel发送OK的应答, 并关闭channel;
  2. 此外需要根据skip和buffer.readableBytes的大小关系, 决定要不要向channel发送buffer

有两点小不足的是:

  1. skip和buffer.readableBytes的大小关系, 如何处理不明了;
  2. if - return 看着不够简洁.

再重构一下:

以下是代码片段:
  public void receive(final ChannelBuffer buffer) throws Exception {
    if (isTail(buffer) && thenSendOkResponseAndClose(channel)) return;
    if (buffer.readableBytes() <= skip && thenSkip(buffer)) return;
    if (skip > 0) skipPartOf(buffer);
    send(buffer);
    skip = 0;
  }

  boolean thenSkip(final ChannelBuffer buffer) {
    skip = skip - buffer.readableBytes();
    return true;
  }

  void send(final ChannelBuffer buffer) {
    channel.write(buffer);
  }

  void skipPartOf(final ChannelBuffer buffer) {
    buffer.skipBytes((int) skip);
  }

  static boolean isTail(final ChannelBuffer buffer) {
    return buffer == null;
  }

  static boolean thenSendOkResponseAndClose(final Channel channel) {
    channel.write(build(OK).response());
    channel.close();
    return true;
  }

尽管代码行数上比最初的版本有了少许增加, 但核心方法receive的意图却变的更为明显了.

建议继续学习

  1. 说说Shell在代码重构中的应用 (阅读 3,842)
  2. 构建前端 DSL (阅读 3,740)
  3. API设计新思维:用流畅接口构造内部DSL (阅读 3,161)
  4. 为脚本语言平反-JavaScript篇(2) (阅读 3,020)
  5. 为脚本语言平反-JavaScript篇(3) (阅读 2,821)
  6. 从Java和JavaScript来学习Haskell和Groovy(DSL) (阅读 2,120)