最近在开发过程中用到了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));
}
}
}