建造者模式 – 设计模式之创建模式:
目录
订单查询参数测试类: OrderParamBuilderTest
定义:
Separate the construction of a complex object from its representation so that the same construction process can create different representations.
建造者模式(Builder Pattern)是将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示,属于创建型模式。使用建造者模式对于用户而言只需指定需要建造的类型就可以获得对象,建造过程及细节不需要了解
类图:
建造者模式通用类图:
在学习建造者模式的时候,我一直没有联想到实际具体可以操作的实例。不过有StringBuilder 可以看看,学习下实际中具体的应用。
StringBuilder:
部分代码:
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
@Override
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
public StringBuilder append(StringBuffer sb) {
super.append(sb);
return this;
}
@Override
public StringBuilder append(CharSequence s) {
super.append(s);
return this;
}
@Override
public StringBuilder append(char[] str) {
super.append(str);
return this;
}
@Override
public StringBuilder append(boolean b) {
super.append(b);
return this;
}
@Override
public StringBuilder append(char c) {
super.append(c);
return this;
}
@Override
public StringBuilder append(int i) {
super.append(i);
return this;
}
@Override
public StringBuilder append(long lng) {
super.append(lng);
return this;
}
@Override
public StringBuilder append(float f) {
super.append(f);
return this;
}
@Override
public StringBuilder append(double d) {
super.append(d);
return this;
}
}
在使用的时候,我们可以append各种类型的数据。这种实现还是很强大的。
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder();
String s = stringBuilder.append(1L).append("y").append(3.0D).append(9.9F).append("px").toString();
System.out.println(s);
}
SqlSessionFactoryBuilder
mybatis 中的建造者模式
我们来看 org.apache.ibatis.session
包下的 SqlSessionFactoryBuilder
类
比如版本: 'org.mybatis:mybatis:3.5.1'
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return build(inputStream, environment, null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
应用场景一:多个参数查询拼接
需求: 根据各种参数查询订单,如根据类型查询订单统计,根据订单单号查询订单详情
思考: 可以用Builder方式,含括所有的参数,然后根据具体的参数进行拼接
订单查询参数类:OrderParam
public class OrderParam {
private String startTime;
private String endTime;
private String orderType;
private String orderSeries;
private String areaCode;
public String getStartTime() {
return startTime;
}
public void setStartTime(String startTime) {
this.startTime = startTime;
}
public String getEndTime() {
return endTime;
}
public void setEndTime(String endTime) {
this.endTime = endTime;
}
public String getOrderType() {
return orderType;
}
public void setOrderType(String orderType) {
this.orderType = orderType;
}
public String getOrderSeries() {
return orderSeries;
}
public void setOrderSeries(String orderSeries) {
this.orderSeries = orderSeries;
}
public String getAreaCode() {
return areaCode;
}
public void setAreaCode(String areaCode) {
this.areaCode = areaCode;
}
public OrderParam(BeanBuilder beanBuilder) {
this.startTime = beanBuilder.startTime;
this.endTime = beanBuilder.endTime;
this.orderType = beanBuilder.orderType;
this.orderSeries = beanBuilder.orderSeries;
this.areaCode = beanBuilder.areaCode;
}
public static class BeanBuilder {
private String startTime;
private String endTime;
private String orderType;
private String orderSeries;
private String areaCode;
public BeanBuilder startTime(String startTime) {
this.startTime = startTime;
return this;
}
public BeanBuilder endTime(String endTime) {
this.endTime = endTime;
return this;
}
public BeanBuilder orderType(String orderType) {
this.orderType = orderType;
return this;
}
public BeanBuilder orderSeries(String orderSeries) {
this.orderSeries = orderSeries;
return this;
}
public BeanBuilder areaCode(String areaCode) {
this.areaCode = areaCode;
return this;
}
// 返回对应的主类
public OrderParam builder() {
return new OrderParam(this);
}
}
@Override
public String toString() {
return "OrderParam{" +
"startTime='" + startTime + '\'' +
", endTime='" + endTime + '\'' +
", orderType='" + orderType + '\'' +
", orderSeries='" + orderSeries + '\'' +
", areaCode='" + areaCode + '\'' +
'}';
}
}
订单查询参数测试类: OrderParamBuilderTest
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
public class OrderParamBuilderTest {
public static void main(String[] agrs) {
OrderParam orderParam = new OrderParam.BeanBuilder().startTime("2021-01-01 00:00:00").endTime("2021-01-05 23:59:59").orderType("es").orderSeries("yan").areaCode("456451")
.builder();
assertNotNull(orderParam);
assertNotNull(orderParam.toString());
System.out.println(orderParam.toString());
assertEquals("123", orderParam.getAreaCode());
}
}
结果:
OrderParam{startTime='2021-01-01 00:00:00', endTime='2021-01-05 23:59:59', orderType='es', orderSeries='yan', areaCode='456451'}
Exception in thread "main" org.opentest4j.AssertionFailedError: expected: <123> but was: <456451>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:52)
at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:177)
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:172)
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:163)
at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:481)
请求参数拼接 OrderController
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@RequestMapping("/order")
public class OrderController {
/**
* 查询订单类型的统计
* @param orderType 订单类型
* @return
*/
@GetMapping("/getOrderTypeStatics")
public Object getOrderTypeStatics(@RequestParam(required = false) String orderType) {
OrderParam orderParam = new OrderParam.BeanBuilder().orderType(orderType).builder();
// 具体业务
return "getOrderTypeStatics 查询回来的值";
}
/**
* 查询订单详情
* @param orderSeries 订单单号
* @param areaCode 区域
* @return
*/
@GetMapping("/getOrderDetail")
public Object getOrderDetail(@RequestParam String orderSeries, @RequestParam(required = false) String areaCode) {
OrderParam orderParam = new OrderParam.BeanBuilder().orderSeries(orderSeries).areaCode(areaCode).builder();
// 具体业务
return "getOrderDetail查询回来的值";
}
/**
* 查询订单列表信息
* @param startTime 开始时间
* @param endTime 结束时间
* @param orderSeries 订单单号
* @param orderType 订单类型
* @param areaCode 区域
* @return
*/
@GetMapping("/getOrderInfo")
public Object getOrderInfo(@RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime,
@RequestParam(required = false) String orderSeries, @RequestParam(required = false) String orderType,
@RequestParam(required = false) String areaCode) {
OrderParam orderParam = new OrderParam.BeanBuilder().startTime(startTime).endTime(endTime).orderSeries(orderSeries).orderType(orderType).areaCode(areaCode).builder();
// 具体业务
return "getOrderInfo 查询回来的值";
}
}
总结:
应用场景之一: 多个查询参数的情况下,用于构建传递参数。
builder模式的不足:
(1)为了创建西对象,必须先创建它的构建器。增加了创建构建器的开销。当然大部分时候创建构建器的开销几乎微不足道。
(2)Builder模式比重叠构造器(不同参数组合的构造器)更加冗长,因此它只适合在很多参数的时候使用。