铁锤的IT奇妙探险 Java Back-End Coder

设计模式之工厂模式


工厂模式包括三种,本文将通过示例和应用对工厂方法模式和简单工厂模式进行讲解。

工厂模式

  • 工厂模式是最常用的一类创建型设计模式,包括 抽象工厂模式,工厂方法模式和简单工厂模式 这三种
  • 典型代表是 SqlSessionFactory,SqlSession 是 MyBatis 中的重要 Java 接口,可以通过该接口来执行 SQL 命令、获取映射器示例和管理事务,而 SqlSessionFactory 正是用来产生 SqlSession 对象的,所以它在 MyBatis 中是比较核心的接口之一。
  • DefaultSqlSessionFactorys 有一个 openSession(ExecutorType execType) 的方法,其调用的 configuration.newExecutor(tx, execType)为标准的工厂模式,它会根据传递 ExecutorType 值生成相应的对象然后进行返回。

    简单工厂模式

    定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式。

角色

  1. Factory(工厂角色):工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象。
  2. Product(抽象产品角色):它是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
  3. 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

工厂方法模式

角色

  1. Product(抽象产品):它是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的公共父类
  2. ConcreteProduct(具体产品):它实现了抽象产品接口,某种类型的具体产品由专门的具体工厂创建,具体工厂和具体产品之间一一对应
  3. Factory(抽象工厂):在抽象工厂类中,声明了工厂方法(Factory Method),用于返回一个产品。抽象工厂是工厂方法模式的核心,所有创建对象的工厂类都必须实现该接口
  4. 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 类。


Similar Posts

Comments