工厂模式包括三种,本文将通过示例和应用对工厂方法模式和简单工厂模式进行讲解。
工厂模式
- 工厂模式是最常用的一类创建型设计模式,包括 抽象工厂模式,工厂方法模式和简单工厂模式 这三种
- 典型代表是 SqlSessionFactory,SqlSession 是 MyBatis 中的重要 Java 接口,可以通过该接口来执行 SQL 命令、获取映射器示例和管理事务,而 SqlSessionFactory 正是用来产生 SqlSession 对象的,所以它在 MyBatis 中是比较核心的接口之一。
- DefaultSqlSessionFactorys 有一个 openSession(ExecutorType execType) 的方法,其调用的 configuration.newExecutor(tx, execType)为标准的工厂模式,它会根据传递 ExecutorType 值生成相应的对象然后进行返回。
简单工厂模式
定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式。
角色
- Factory(工厂角色):工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象。
- Product(抽象产品角色):它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
- ConcreteProduct(具体产品角色):它是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。
//抽象产品类
public abstract class Video {
public abstract void produce();
}
//两个具体产品类
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("录制Java课程视频");
}
}
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("录制Python课程视频");
}
}
//工厂
public class VideoFactory {
/**
* 使用if else 判断类型,type 为 Java 则返回 JavaVideo, type为Python则返回 PythonVideo
*/
public Video getVideo(String type) {
if ("java".equalsIgnoreCase(type)) {
return new JavaVideo();
} else if ("python".equalsIgnoreCase(type)) {
return new PythonVideo();
}
return null;
}
/**
* 使用反射来创建对象
*/
public Video getVideo(Class c) {
Video video = null;
try {
video = (Video) Class.forName(c.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return video;
}
}
//测试工厂类
public class Test {
public static void main(String[] args) {
VideoFactory videoFactory = new VideoFactory();
Video video1 = videoFactory.getVideo("python");
if (video1 == null) {
return;
}
video1.produce();
Video video2 = videoFactory.getVideo(JavaVideo.class);
if (video2 == null) {
return;
}
video2.produce();
}
}
- 适用场景:
- 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
- 客户端只知道传入工厂类的参数,对于如何创建对象并不关心。
应用JDBC 获取数据库连接
Class.forName("com.mysql.jdbc.Driver");
DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test", "root", "123456");
首先通过反射加载驱动类 com.mysql.jdbc.Driver 类,然后再通过 DriverManager 获取连接
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
public Driver() throws SQLException {
}
static {
try {
//new 一个 Driver 类并注册到 DriverManager 驱动管理类中
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
}
通过 DriverManager.getConnection 获取连接对象的主要代码如下:通过for循环从已注册的驱动中(registeredDrivers)获取驱动,尝试连接,成功则返回连接
private static Connection getConnection(String url, java.util.Properties info, Class<?> caller) throws SQLException {
// ...省略...
println("DriverManager.getConnection(\"" + url + "\")");
for(DriverInfo aDriver : registeredDrivers) {
if(isDriverAllowed(aDriver.driver, callerCL)) {
try {
println(" trying " + aDriver.driver.getClass().getName());
Connection con = aDriver.driver.connect(url, info);
if (con != null) {
// Success!
println("getConnection returning " + aDriver.driver.getClass().getName());
return (con);
}
} catch (SQLException ex) {
if (reason == null) {
reason = ex;
}
}
} else {
println(" skipping: " + aDriver.getClass().getName());
}
}
}
工厂角色为 DriverManager 类,抽象产品角色为 Connection
工厂方法模式
角色
- Product(抽象产品):它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类
- ConcreteProduct(具体产品):它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应
- Factory(抽象工厂):在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口
- ConcreteFactory(具体工厂):它是抽象工厂类的子类,实现了抽象工厂中定义的工厂方法,并可由客户端调用,返回一个具体产品类的实例
示例
抽象产品类
public abstract class Video { public abstract void produce(); }
具体产品类 JavaVideo 和 PythonVideo,需要继承抽象产品类 Video
public class JavaVideo extends Video {
@Override
public void produce() {
System.out.println("录制Java课程视频");
}
}
public class PythonVideo extends Video {
@Override
public void produce() {
System.out.println("录制Python课程视频");
}
}
抽象工厂类 VideoFactory
public abstract class VideoFactory {
public abstract Video getVideo();
}
具体工厂类 JavaVideoFactory 和 PythonVideoFactory,需要继承抽象工厂类 VideoFactory
public class JavaVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
}
public class PythonVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
}
客户端类,需要什么产品则通过该产品对应的工厂类来获取,不需要知道具体的创建过程
public class Test {
public static void main(String[] args) {
VideoFactory pythonVideoFactory = new PythonVideoFactory();
VideoFactory javaVideoFactory = new JavaVideoFactory();
Video pythonVideo = pythonVideoFactory.getVideo();
pythonVideo.produce();
Video javaVideo = javaVideoFactory.getVideo();
javaVideo.produce();
}
}
当需要增加一个产品 FEVideo 时,只需要增加 FEVideo 具体产品类和 FEVideoFactory 具体工厂类即可,不需要修改原有的产品类和工厂类
public class FEVideo extends Video{
@Override
public void produce() {
System.out.println("录制FE课程视频");
}
}
public class FEVideoFactory extends VideoFactory{
@Override
public Video getVideo() {
return new FEVideo();
}
}
利用反射机制的客户端类
public class Test {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// 从文件或数据库等外部渠道获取 工厂类名
String factoryName = "com.designpattern.factorymethod.JavaVideoFactory";
// 通过反射机制获取工厂类
Class c = Class.forName(factoryName);
VideoFactory factory = (VideoFactory)c.newInstance();
// 生产产品
Video video = factory.getVideo();
video.produce();
}
}
集合接口 Collection
集合接口中有一个iterator方法
public interface Collection<E> extends Iterable<E> {
Iterator<E> iterator();
// ...省略
}
查看java.util.ArrayList对 iterator 方法的实现
public Iterator<E> iterator() {
return new Itr();
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
Itr() {}
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
// ...省略...
}
public void remove() {
// ...省略...
}
}
Itr 类实现了 Iterator 接口,Iterator 接口正是 Collection 接口中 iterator 方法的返回类型,由此可见,Collection 接口扮演了抽象工厂角色,工厂方法为 iterator(),Collection 的实现类譬如 ArrayList 扮演了具体工厂角色,而抽象产品为 Iterator 接口,具体产品为 Itr 类。