Java设计模式之——抽象工厂方法

导语

上一篇文章《Java设计模式之——工厂方法》中对工厂方法进行了一个简单的概述,那么本篇将开始阐述一下抽象工厂方法的概念,以及它在jdk等源码中的使用。

对于抽象工厂而言,它实际上是工厂方法的一个升级版,在有多个业务品种、业务类型时,通过抽象工厂来生产所需要的对象,实际上是一中非常好的解决方式。且工厂方法是为了解决产品等级结构这样一个问题的方法,但是抽象工厂方法解决的是产品族这样一个概念的工厂方法。

 

一、抽象工厂方法的定义和类型

定义:抽象工厂模式提供一个创建一系列相关或相互依赖的接口,无需指定其他具体的类

类型:创建类型

 

二、抽象工厂方法的适用场景和优缺点

适用场景:

  • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
  • 强调一系列相关的产品对象(属于同一产品族),一起使用创建对象需要大量重复的代码

优点:

  • 具体产品在应用层代码隔离,无需关心创建细节
  • 将一个系列的产品族统一到一起创建

缺点:

  • 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
  • 增加了系统的抽象性和难度

三、抽象工厂方法UML类图和具体代码实现

1.首先创建同一产品族中的两个抽象产品类

video类:

public abstract class Video {
    public abstract void produce();
}

手记类:

public abstract class Notes {
    public abstract void produce();
}

2.定义产品具体的实现类

video的实现类:

// JavaVideo 的实现类
public class JavaVideo extends Video {
    @Override
    public void produce() {
        System.out.println("-----录制Java视频课程-----");
    }
}

// PythonVideo 的实现类
public class PythonVideo extends Video {
    @Override
    public void produce() {
        System.out.println("-----录制Python视频课程-----");
    }
}

手记的实现类:

// JavaNotes 的实现类
public class JavaNotes extends Notes {
    @Override
    public void produce() {
        System.out.println("-----编写Java手记-----");
    }
}

// PythonNotes 的实现类
public class PythonNotes extends Notes {
    @Override
    public void produce() {
        System.out.println("-----编写Python手记-----");
    }
}

3.定义具体产品的工厂类

public class JavaCourseFactory  implements CourseFactory {
    @Override
    public Video getVideo() {
        return new JavaVideo();
    }

    @Override
    public Notes getNotes() {
        return new JavaNotes();
    }
}
public class PythonCourseFactory implements CourseFactory {
    @Override
    public Video getVideo() {
        return new PythonVideo();
    }

    @Override
    public Notes getNotes() {
        return new PythonNotes();
    }
}

4.测试类

public class MainTest {
    public static void main(String[] args) {
        CourseFactory courseFactory = new JavaCourseFactory();
        Video  video = courseFactory.getVideo();
        Notes note = courseFactory.getNotes();
        video.produce();
        note.produce();
    }
}

测试结果:

 

四、抽象工厂方法在JDK源码中的体现

在学习ORM框架时,大多数人都是接触过mybatis这个框架的,那么对于这个框架中含有抽象工厂方法的使用,相信很多人也是知道的。

在mybatis中有这样的一个接口SqlSessionFactory,接口中定义了很多session相关的方法,每个方法传入的相对应的参数都和其具体实现有关系,代码如下:

public interface SqlSessionFactory {

  SqlSession openSession();

  SqlSession openSession(boolean autoCommit);
  SqlSession openSession(Connection connection);
  SqlSession openSession(TransactionIsolationLevel level);

  SqlSession openSession(ExecutorType execType);
  SqlSession openSession(ExecutorType execType, boolean autoCommit);
  SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level);
  SqlSession openSession(ExecutorType execType, Connection connection);

  Configuration getConfiguration();

}

我们可以查看这个接口的具体实现,有SqlSessionManager和DefaultSqlSessionFactory,这里打开DefaultSqlSessionFactory这个实现类,这个类中的实现代码较长,这里就不贴具体代码了,选一个方法进行简单的阐述,代码如下:

public class DefaultSqlSessionFactory implements SqlSessionFactory {

  private final Configuration configuration;

  public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
  }

// 具体其他代码省略

  @Override
  public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
    return openSessionFromDataSource(execType, level, false);
  }


  private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
    Transaction tx = null;
    try {
      final Environment environment = configuration.getEnvironment();
      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
      tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
      final Executor executor = configuration.newExecutor(tx, execType);
      return new DefaultSqlSession(configuration, executor, autoCommit);
    } catch (Exception e) {
      closeTransaction(tx); // may have fetched a connection so lets call close()
      throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

// 其他具体代码省略

}

从上述代码中,可以看到openSession(ExecutorType execType, TransactionIsolationLevel level)这个重载的方法的代码中调用了openSessionFromDataSource(execType, level, false)这个方法,从这个方法的代码中,可以看大具体步骤如下:

  1. 首先通过configuration获取环境变量
  2. 再通过环境变量作为参数获取事务的工厂
  3. 通过环境变量等一些相关参数获取事务
  4. 通过事务和execType作为参数来新建一个执行器
  5. 最后通过configuration、executor、autoCommit这些相关参数来得到DefaultSqlSession

最后可以看出,虽然方法上所返回的SqlSession这个对象,但实际上所返回的是DefaultSqlSession这个对象。其实在平常的源码阅读中,可以多注意一些框架的设计原理和思想,这学习的进阶有很大的帮助。

发布了41 篇原创文章 · 获赞 8 · 访问量 4272

猜你喜欢

转载自blog.csdn.net/zfy163520/article/details/91360958