从 Mybatis 源码中,学习到的 10 种设计模式(一)

一、前言:小镇卷码家

“为什么学设计模式、看框架源码、补技术知识,就一个普通的业务项目,会造飞机不也是天天写 CRUD 吗?”

你说的没错,但你天天写 CRUD,你觉得 烦不? 慌不? 是不是既担心自己没有得到技术成长,也害怕将来没法用这些都是 CRUD 的项目去参加;述职、晋升、答辩,甚至可能要被迫面试时,自己手里一点干货也没有的情况。

当然要扩充自己的知识储备,否则架构,架构思维不懂设计,设计模式不会源码、源码学习不深,最后就用一堆 CRUD 写简历吗?

二、源码:学设计模式

在 Mybatis 两万多行的框架源码实现中,使用了大量的设计模式来解耦工程架构中面对复杂场景的设计,这些是设计模式的巧妙使用才是整个框架的精华,有如下 10 种设计模式的使用,如图所示

讲道理,如果只是把这 10 种设计模式背下来,等着下次面试的时候拿出来说一说,虽然能有点帮助,不过这种学习方式就真的算是把路走窄了。就像你每说一个设计模式,能联想到这个设计模式在 Mybatis 的框架中,体现到哪个流程中的源码实现上了吗?这个源码实现的思路能不能用到你的业务流程开发里?别总说你的流程简单,用不上设计模式!难到因为有钱、富二代,就不考试吗?🤔

 三、类型:创建型模式

1. 工厂模式

源码详见cn.bugstack.mybatis.session.SqlSessionFactory

public interface SqlSessionFactory {
   SqlSession openSession();
}

复制代码

源码详见cn.bugstack.mybatis.session.defaults.DefaultSqlSessionFactory

public class DefaultSqlSessionFactory implements SqlSessionFactory {
    private final Configuration configuration;
    public DefaultSqlSessionFactory(Configuration configuration) {        this.configuration = configuration;    }
    @Override    public SqlSession openSession() {        Transaction tx = null;        try {            final Environment environment = configuration.getEnvironment();            TransactionFactory transactionFactory = environment.getTransactionFactory();            tx = transactionFactory.newTransaction(configuration.getEnvironment().getDataSource(), TransactionIsolationLevel.READ_COMMITTED, false);            // 创建执行器            final Executor executor = configuration.newExecutor(tx);            // 创建DefaultSqlSession            return new DefaultSqlSession(configuration, executor);        } catch (Exception e) {            try {                assert tx != null;                tx.close();            } catch (SQLException ignore) {            }            throw new RuntimeException("Error opening session.  Cause: " + e);        }    }
}

复制代码

  • 工厂模式:简单工厂,是一种创建型设计模式,其在父类中提供一个创建对象的方法,允许子类决定实例对象的类型。

  • 场景介绍SqlSessionFactory 是获取会话的工厂,每次我们使用 Mybatis 操作数据库的时候,都会开启一个新的会话。在会话工厂的实现中负责获取数据源环境配置信息、构建事务工厂、创建操作 SQL 的执行器,并最终返回会话实现类。

  • 同类设计SqlSessionFactoryObjectFactoryMapperProxyFactoryDataSourceFactory

2. 单例模式

源码详见cn.bugstack.mybatis.session.Configuration

public class Configuration {
    // 缓存机制,默认不配置的情况是 SESSION    protected LocalCacheScope localCacheScope = LocalCacheScope.SESSION;
    // 映射注册机    protected MapperRegistry mapperRegistry = new MapperRegistry(this);
    // 映射的语句,存在Map里    protected final Map<String, MappedStatement> mappedStatements = new HashMap<>();    // 缓存,存在Map里    protected final Map<String, Cache> caches = new HashMap<>();    // 结果映射,存在Map里    protected final Map<String, ResultMap> resultMaps = new HashMap<>();    protected final Map<String, KeyGenerator> keyGenerators = new HashMap<>();
    // 插件拦截器链    protected final InterceptorChain interceptorChain = new InterceptorChain();
    // 类型别名注册机    protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();    protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();
    // 类型处理器注册机    protected final TypeHandlerRegistry typeHandlerRegistry = new TypeHandlerRegistry();
    // 对象工厂和对象包装器工厂    protected ObjectFactory objectFactory = new DefaultObjectFactory();    protected ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();
    protected final Set<String> loadedResources = new HashSet<>();     //...}

复制代码

  • 单例模式:是一种创建型模式,让你能够保证一个类只有一个实例,并提供一个访问该实例的全局节点。

  • 场景介绍:Configuration 就像狗皮膏药一样大单例,贯穿整个会话的生命周期,所以的配置对象;映射、缓存、入参、出参、拦截器、注册机、对象工厂等,都在 Configuration 配置项中初始化。并随着 SqlSessionFactoryBuilder 构建阶段完成实例化操作。

  • 同类场景ErrorContextLogFactoryConfiguration

3. 建造者模式

源码详见cn.bugstack.mybatis.mapping.ResultMap#Builder

public class ResultMap {
    private String id;    private Class<?> type;    private List<ResultMapping> resultMappings;    private Set<String> mappedColumns;
    private ResultMap() {    }
    public static class Builder {        private ResultMap resultMap = new ResultMap();
        public Builder(Configuration configuration, String id, Class<?> type, List<ResultMapping> resultMappings) {            resultMap.id = id;            resultMap.type = type;            resultMap.resultMappings = resultMappings;        }
        public ResultMap build() {            resultMap.mappedColumns = new HashSet<>();            // step-13 新增加,添加 mappedColumns 字段            for (ResultMapping resultMapping : resultMap.resultMappings) {                final String column = resultMapping.getColumn();                if (column != null) {                    resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH));                }            }            return resultMap;        }
    }        // ... get}

复制代码

  • 建造者模式:使用多个简单的对象一步一步构建成一个复杂的对象,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

  • 场景介绍:关于建造者模式在 Mybatis 框架里的使用,那真是纱窗擦屁股,给你漏了一手。到处都是 XxxxBuilder,所有关于 XML 文件的解析到各类对象的封装,都使用建造者以及建造者助手来完成对象的封装。它的核心目的就是不希望把过多的关于对象的属性设置,写到其他业务流程中,而是用建造者的方式提供最佳的边界隔离。

  • 同类场景SqlSessionFactoryBuilderXMLConfigBuilderXMLMapperBuilderXMLStatementBuilderCacheBuilder

  • ```python
    class BertPooler(nn.Module):
        def __init__(self, config):
            super().__init__()
            self.dense = nn.Linear(config.hidden_size, config.hidden_size)
            self.activation = nn.Tanh()
    
        def forward(self, hidden_states):
            # We "pool" the model by simply taking the hidden state corresponding
            # to the first token.
            first_token_tensor = hidden_states[:, 0]
            pooled_output = self.dense(first_token_tensor)
            pooled_output = self.activation(pooled_output)
            return pooled_output
    from transformers.models.bert.configuration_bert import *
    import torch
    config = BertConfig.from_pretrained("bert-base-uncased")
    bert_pooler = BertPooler(config=config)
    print("input to bert pooler size: {}".format(config.hidden_size))
    batch_size = 1
    seq_len = 2
    hidden_size = 768
    x = torch.rand(batch_size, seq_len, hidden_size)
    y = bert_pooler(x)
    print(y.size())
    ```

  • 32
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值