Loading

设计模式实战——开发中经常涉及到的建造者模式

本系列博客是自己在学习设计模式过程中收集整理的文章集合,其他文章参看设计模式传送门

建造者模式简介

建造者模式是一种创建型设计模式,这种模式具有很好的封装性。使用建造者模式可以有效的封装变化,在使用建造者模式的场景中,一般产品类和建造者类是比较稳定的,因此,将主要的业务逻辑封装在导演类中对整体而言可以取得比较好的稳定性。

在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。

可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。

其次,建造者模式很容易进行扩展。如果有新的需求,通过实现一个新的建造者类就可以完成,基本上不用修改之前已经测试通过的代码,因此也就不会对原有功能引入风险。符合开闭原则。

建造者模式通常包含以下角色

抽象建造者类(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:需要被创建的产品

感悟

学习设计模式光学习不行,因为这个东西比较抽象。你必须结合具体的项目框架来看才能有比较深的感悟。

平时如果有空余时间可以自己动手,使用设计模式写一些小的框架。还有就是多看看那些主流开源框架的源代码,这些代码中都有很对设计模式的体现。结合设计模式的理论知识,看看这些框架中为什么要用这些模式,比你光看肯定收获要多。

posted @ 2020-03-04 14:49  程序员自由之路  阅读(1550)  评论(0编辑  收藏  举报