本系列博客是自己在学习设计模式过程中收集整理的文章集合, 其他文章参看设计模式传送门
建造者模式简介
建造者模式是一种创建型设计模式, 这种模式具有很好的封装性. 使用建造者模式可以有效的封装变化, 在使用建造者模式的场景中, 一般产品类和建造者类是比较稳定的, 因此, 将主要的业务逻辑封装在导演类中对整体而言可以取得比较好的稳定性.
在建造者模式中, 客户端不必知道产品内部组成的细节, 将产品本身与产品的创建过程解耦, 使得相同的创建过程可以创建不同的产品对象.
可以更加精细地控制产品的创建过程 . 将复杂产品的创建步骤分解在不同的方法中, 使得创建过程更加清晰, 也更方便使用程序来控制创建过程.
其次, 建造者模式很容易进行扩展. 如果有新的需求, 通过实现一个新的建造者类就可以完成, 基本上不用修改之前已经测试通过的代码, 因此也就不会对原有功能引入风险. 符合开闭原则.
建造者模式通常包含以下角色
抽象建造者类 (builder): 为创建 product 对象而指定各个组件的抽象接口
具体建造类 (concreteBuilder): 实现 builder 接口, 重写方法构建不同的表示
产品类 (product): 具体的产品
指挥者类 (director): 构建一个使用 builder 接口的对象
JDK 中的建造者模式 --StringBuilder
StringBuilder 类是 JDK 中比较典型的建造者模式的体现. 我先看下这个类的类图:
我们根据上图看下各个角色的对应情况:
StringBuilder: 指挥者角色, 持有具体建造者的引用, 由于 StringBuilder 继承了 AbstractStringBuilder, 这里 StringBuilder 通过 super 来作为具体建造者的引用.
AbstractStringBuilder: 具体建造者, 它实现了 appendable 接口的 append(Character c) 方法.
Appendable: 抽象建造者, 定义了创建对象的接口.
String: 产品角色.
另外, StringBuffer 也是使用了建造者模式. 两者的唯一区别就是 StringBuffer 使用了 synchronized 来保证线程安全, 而 StringBuilder 不是线程安全的.
其实, 建造者模式在我们平时开发中更多的体现就是像 StringBuilder.append 这样的链式调用. 其中 StringBuilder 就是指挥官角色, append 方法是创建产品细节的过程, 当我们创建完产品后就可以调用 toString 方法生成具体的产品. 比如下面的代码
- String str = new StringBuilder().append()
- .append()
- .toString();
这样类似的代码还有很多, 比如
- Header header = new HeaderBuilder()
- .setClientId(SOAHeader.SOAP_CLIENT_ID)
- .setCorrelationId(SOAHeader.SOAP_CORRELATION_ID)
- .buildHeader();
在平时开发过程中, 如果我们看到上面类似的代码, 可能就是用了建造者模式. 我们平时要留意这样的代码, 看看作者为什么要这样设计系统, 对我们的代码提升很有帮助. 这也是我整理总结开发框架中常见设计模式的用意.
Spring 中的建造者模式
Spring 是 Java 开发者最常用的开发框架. 有人说 Spring 的源代码就是设计模式的盛宴. 看 Spring 的源代码是很好的学习设计模式的一种方式.
在 Spring 框架中, 常涉及到的建造者模式有:
- UriComponentsBuilder
- BeanDefinitionBuilder
其中 BeanDefinitionBuilder 较底层, 我们平时不太会用到. 这里我们通过 UriComponentsBuilder 来讲述 Spring 中的建造者模式.
下面的代码中, 我们 Spring 中的 restTemplate 工具调用远程接口. 在调用前需要先构建 URL 参数. 这边就是使用了 UriComponentsBuilder 来构建的.
- UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl("127.0.0.1:8080").
- path("/test").build(true);
- URI uri = uriComponents.toUri();
- RequestEntity<JSONObject> requestEntity = RequestEntity.post(uri).
- // 添加 cookie(这边有个问题, 假如我们要设置 cookie 的生命周期, 作用域等参数我们要怎么操作)
- header(HttpHeaders.COOKIE,"key1=value1").
- // 添加 header
- header(("MyRequestHeader", "MyValue")
- accept(MediaType.APPLICATION_JSON).
- contentType(MediaType.APPLICATION_JSON).
- body(requestParam);
- ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(requestEntity,JSONObject.class);
- // 响应结果
- JSONObject responseEntityBody = responseEntity.getBody();
Spring 中的设计模式有很多, 我们平时使用时可以细心关注下. 相信肯定会有收获.
MyBatis 中的建造者模式
MyBatis 中最经典的建造者模式肯定是获取 SqlSessionFactory 的过程.
下面是获取 SqlSessionFactory 的典型用法.
- CopyClassPathResource resource = new ClassPathResource("mybatis-config.xml");
- InputStream inputStream = resource.getInputStream();
- sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
通过上面代码发现, 创建 SqlSessionFactory 的代码在 SqlSessionFactoryBuilder 中, 进去一探究竟:
- Copy// 整个过程就是将配置文件解析成 Configration 对象, 然后创建 SqlSessionFactory 的过程
- //Configuration 是 SqlSessionFactory 的一个内部属性
- 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);
- }
代码比较简单, 就不具体分析了. 这里还是对号入座, 列举下各个角色.
SqlSessionFactoryBuilder: 指挥者角色
BaseBuilder: 抽象 Builder
XMLConfigBuilder: 具体的 Builder
SqlSessionFactory: 需要被创建的产品
感悟
学习设计模式光学习不行, 因为这个东西比较抽象. 你必须结合具体的项目框架来看才能有比较深的感悟.
平时如果有空余时间可以自己动手, 使用设计模式写一些小的框架. 还有就是多看看那些主流开源框架的源代码, 这些代码中都有很对设计模式的体现. 结合设计模式的理论知识, 看看这些框架中为什么要用这些模式, 比你光看肯定收获要多.
来源: https://www.cnblogs.com/54chensongxia/p/12409493.html