Skip to content

Instantly share code, notes, and snippets.

@xcaspar
Last active August 29, 2015 14:25
Show Gist options
  • Save xcaspar/f12b72e89d45aec4b8fe to your computer and use it in GitHub Desktop.
Save xcaspar/f12b72e89d45aec4b8fe to your computer and use it in GitHub Desktop.

流式Builder模式

最近在开发过程中用到了builder模式,比如订单创建、道具发送参数创建等,传统的builder模式已被大家熟知,传统的构建模式专注于抽象的构建步骤(详见附录A),现在介绍一下fluent builder.
fluent builder源于Martin Fowler的这篇文章:FluentInterface,它专注于属性值的设置,不需要繁琐的setter方法和参数构造器就可以完成对象的创建和校验。实例如下:
实体类的写法(为了篇幅,以下去掉了注释):

public class Order implements Serializable {
    private static final long serialVersionUID = 7820429648874014638L;
    private Long id;
    private String orderSn;
    private String partner;
    private String paySn;
    private String deliverSn;
    // 省略其它属性...
    // getters方法
  
    private Order(OrderBuilder builder) {
      this.id = builder.id;
      this.orderSn = builder.orderSn;
      this.partner = builder.partner;
      this.paySn = builder.paySn;
      this.deliverSn = builder.deliverSn;
      // ...
    }
    // build构造器
    public static class OrderBuilder{
        private Long id;
        private String orderSn;
        private String partner;
        private String paySn;
        private String deliverSn;
        // ...
        public OrderBuilder withId(Long id) {
          this.id = id;
          return this;
        }
        public OrderBuilder withOrderSn(String orderSn) {
          this.orderSn = orderSn;
          return this;
        }
        public OrderBuilder withPartner(String partner) {
          this.partner = partner;
          return this;
        }
        public OrderBuilder withPaySn(String paySn) {
          this.paySn = paySn;
          return this;
        }
        public OrderBuilder withDeliverSn(String deliverSn) {
          this.deliverSn = deliverSn;
          return this;
        }
        // ....
        public Order build() {
          validate();
          return new Order(this);
        }
        private void validate() {
        // XXX 此处可对必要参数进行校验
        }
        // 也可以调用一个参数构造器对必要参数进行添加,如下:
        public OrderBuilder (String orderSn) {
            this.orderSn = orderSn;
        }
    }

构建对象的时候,直接链式调用:
Order order = new Order.OrderBuilder(orderSn).withBuyerId(tradeUser.getUserId()).withBuyerAccount(tradeUser.getAccount()).withSellerAccount(goods.getSellerAccount())....build();

这样写代码易读,而且能灵活的创建对象,而且能方便的添加各种约束。
有相应的eclipse插件可以快速生成所需要的实体: - https://code.google.com/a/eclipselabs.org/p/bob-the-builder/ - https://code.google.com/p/fluent-builders-generator-eclipse-plugin/

####附录A 创建一个构造接口:

  public interface RawDeliverItemBuilder {
      /**
       * 省略 <br/>
       */public void buildGameServerVO(Integer platformId, Integer gameId, String worldId,
                  String worldName, String serverId, String serverName, String groupId);
      /**
       *省略
       */public void buildAccountVO(String account, String cnMaster);
      // 省略其它...
  }

设置一个需要构建的实体:
public class RawDeliverItem {
    /**
     * 区服信息
     */protected GameServerVO gameServerVO;
    /**
     * 购买者账号信息
     */protected AccountVO accountVO;
    /**
     * 订单信息
     */protected ApiOrderVO apiOrderVO;
    /**
     * 游戏角色信息
     */protected GameChar gameChar;
    /**
     * IP信息
     */protected LocationInfo locationInfo;
    /**
     * 其它参数
     */protected OtherParam otherParam;
    // set,get方法
}

设置一个接口执行者(由于我这里区分B2C和C2C,所以抽象出一个对象去实现接口):
public abstract class AbstractRawDeliverItemBuilder implements RawDeliverItemBuilder{
    protected RawDeliverItem rawDeliverItem;
    private List<String> processList;
    public AbstractRawDeliverItemBuilder() {
        rawDeliverItem = new RawDeliverItem();
        processList = new ArrayList<String>();
    }
    public RawDeliverItem getRawDeliverItem() {
        validateProcessList(processList);
        processList = null;
        return this.rawDeliverItem;
    }
    protected String GAMESERVERVO_PROCESS = "gameServerVO_process";
    // ...省略其它校验    protected abstract void validateProcessList(List<String> processList);
    @Override
    public void buildGameServerVO(Integer platformId, Integer gameId,
            String worldId, String worldName, String serverId,
            String serverName, String groupId) {
        GameServerVO gameServerVO = new GameServerVO();
        gameServerVO.setPlatformId(platformId);
        gameServerVO.setGameId(gameId);
        gameServerVO.setWorldId(worldId);
        gameServerVO.setWorldName(worldName);
        gameServerVO.setServerId(serverId);
        gameServerVO.setServerName(serverName);
        gameServerVO.setGroupId(groupId);
        rawDeliverItem.setGameServerVO(gameServerVO);
        processList.add(GAMESERVERVO_PROCESS);
    }
    ...
}

实现校验:
public class B2CRawDeliverItemBuilder extends AbstractRawDeliverItemBuilder{
    private List<String> processes;
    public B2CRawDeliverItemBuilder() {
      processes = new ArrayList<String>();
      processes.add(GAMESERVERVO_PROCESS);
      processes.add(APIORDERVO_PROCESS);
      processes.add(GAMECHAR_PROCESS);
      processes.add(ACCOUNTVO_PROCESS);
      processes.add(LOCATIONINFO_PROCESS);
    }
    @Override
    protected void validateProcessList(List<String> processList) {
        if (!processList.containsAll(processes)) {
            throw new OrderException(new OrderResult(OrderResultCode.B2C_DELIVER_PARAM_LESS));
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment