IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

基于DSL风格的代码重构

淘宝数据平台团队 2010-10-28 07:31:53 累计浏览 2,923 次
本机暂存

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

正因如此, 本文仅仅呈现一下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. 等了十年的 Go 链式管道,终于来了:seq 让你像写 Scala 一样写 Go (2026-06-25 18:38:18)
  2. Go 实验特性详解 (2026-06-21 10:05:27)
  3. amd64 微架构级别对 Go 程序性能提升多少? (2026-06-21 09:38:49)

查看更多 后端 文章 →

建议继续学习

  1. 如何成为Python高手 (累计阅读 54,992)
  2. 规范自己的JavaScript书写 (累计阅读 7,088)
  3. PHP编码规范 (累计阅读 5,617)
  4. 关于身份证号的那些事 (累计阅读 5,505)
  5. 为什么编码规范里要求每行代码不超过80个字符的限制是合理的 (累计阅读 4,839)
  6. 构建前端 DSL (累计阅读 3,883)
  7. 编码规范集锦 (累计阅读 3,826)
  8. 如何编写高质量的Javascript代码 (累计阅读 3,750)
  9. 编码风格不是编码规范 (累计阅读 3,657)
  10. 为脚本语言平反-JavaScript篇(2) (累计阅读 3,161)