欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

简单工厂模式与工厂方法模式以及Mybatis中工厂模式的使用

程序员文章站 2024-03-15 19:42:30
...

一、简单工厂模式

Java是一门面向对象的语言。有很多时候我们需要去生产对象,工厂模式就是我们生产对象的一种方式。

简单工厂模式与工厂方法模式以及Mybatis中工厂模式的使用

比如这样一个场景: 我们需要做一个两个数之间的运算,但我们不知道用户究竟要使用哪种运算符对其进行运算。我们就可以使用工厂模式,对用户的选择做一个判断,从而只返回一个用户需要的结果。

第一步,操作实体类,封装两个运算数:

注意@Data注解,它方便的使得我们不用手动构造getter、setter、equals、hashcode、toString、全量构造方法等方法。

@Data
public abstract class Operation {

    private Integer numA;
    private Integer numB;

    public abstract double getResult();

}

第二步,构建不同的操作方法类,构建加减乘除四种不同的方法,我以加法举例

public class OperationAdd extends Operation {


    @Override
    public double getResult() {
        return super.getNumA() + super.getNumB();
    }


}

第三步:简单工厂类

public class OperationFactory {

    public static Operation createOperation(String operate){

        Operation operation = null;
        switch (operate){
            case "+" : operation = new OperationAdd();break;
            case "-" : operation = new OperationSub();break;
            case "*" : operation = new OperationMul();break;
            case "/" : operation = new OperationDiv();break;
            default : new OperationAdd();
        }

        return operation;
    }
}
如上,一个简单的工厂模式就构建完成了。

测试用例如下:

public class SimpleFactroyTest {

    @Test
    public void factoryTest(){
        Operation oper = OperationFactory.createOperation("+");
        oper.setNumA(1);
        oper.setNumB(2);
        System.out.println(oper.getResult());
    }
}

二、工厂方法模式

工厂方法模式,就是给工厂再进一步的抽象。这样可以更灵活,扩展起来也是更加方便。

简单工厂模式与工厂方法模式以及Mybatis中工厂模式的使用

实例如下:

首先:有一个*工厂类,让其他的类继承此工厂类

public interface IFactory {
    
    Operation creatOperation();
    
}

其次:创建对应的工厂的子类

/**
 * 加法工厂
 * */
public class FactoryOperationAdd implements IFactory {

    /**
     * 加法操作
     * */
    @Override
    public Operation creatOperation() {
        return new OperationAdd();
    }

}

对应的工厂的子类去生产对应的操作方法,测试用类如下:

public class MethodFactoryTest {

    /**
     * 工厂方法模式
     * 可以更好的解耦。如果使用简单工厂模式,多了一个开方的业务,我们需要对简单工厂的代码进行修改
     * 而使用工厂方法模式,我们只需要再新建一个类去执行相关的业务就好了
     * 而不用源代码进行修改。
     * */
    @Test
    public void methodTest(){
        IFactory iFactory = new FactoryOperationAdd();
        Operation operation = iFactory.creatOperation();
        operation.setNumA(1);
        operation.setNumB(2);
        System.out.println(operation.getResult());
    }
}

三、MyBatis中工厂模式的使用

在MyBatis中获取DataSource时,我们将DataSource相关的数据封装到MyBatis的配置文件中,MyBatis在初始化时,会去读取配置文件中的信息。Mybatis会根据用户的在配置文件的配置,动态的生成DataSource。生成Datasource的过程就使用了工厂模式。我们来看一下源码:

首先:有一个对工厂的抽象接口类

public interface DataSourceFactory {

  void setProperties(Properties props);

  DataSource getDataSource();

}

其次,根据不同类型的DataSource,建立不同的DataSourceFactory

简单工厂模式与工厂方法模式以及Mybatis中工厂模式的使用

最后:

通过不同的配置生成不同的DataSourceFactory,从而通过不同的DataSourceFactory建立不同类型的DataSource

rivate void environmentsElement(XNode context) throws Exception {
    if (context != null) {
      if (environment == null) {
        environment = context.getStringAttribute("default");
      }
      for (XNode child : context.getChildren()) {
        String id = child.getStringAttribute("id");
        if (isSpecifiedEnvironment(id)) {
          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
          DataSource dataSource = dsFactory.getDataSource();
          Environment.Builder environmentBuilder = new Environment.Builder(id)
              .transactionFactory(txFactory)
              .dataSource(dataSource);
          configuration.setEnvironment(environmentBuilder.build());
        }
      }
    }
  }
看到这里工厂模式就结束了,对源码的分析一定要定焦。就是我想知道哪个部分是如何实现的,我就关心这一部分。这样才能高效的读懂源码,而不被源码拐偏。

如果有好奇的小伙伴,我们顺路来分析一波

dataSourceElement
方法的实现:源码如下:
  private DataSourceFactory dataSourceElement(XNode context) throws Exception {
    if (context != null) {
      String type = context.getStringAttribute("type");  // 读取XML中type的标签
      Properties props = context.getChildrenAsProperties();  // 读取子节点作为配置
       // 根据type新建一个DataSourceFatory的实际例子
      DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
      factory.setProperties(props);
      return factory;
    } 
  } 


这时候我们不妨看看xml中Datasource是如何配置的:

 <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
  </dataSource>
再跟源码:

protected Class<?> resolveClass(String alias) {
    if (alias == null) {
      return null;
    }
    try {
      return resolveAlias(alias);
    } catch (Exception e) {
      throw new BuilderException("Error resolving class. Cause: " + e, e);
    }
  }
再往后还有一些细节,最终我们发现,它是从一张别名表,通过别名表里的配置,去加载到相对应得类,而去创建对象的。

typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
    typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
    typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class);