设计模式:MyBatis中的抽象工厂

简介

介绍抽象工厂之前,需要先介绍两个概念:产品族和产品等级。产品族是指同一主题的产品,例如Java的录像和Java的文章都属于Java主题的产品,他们将在同一个工厂生产。产品等级是指不同产品族中的同类产品,比如Java的录像和Python的录像,他们分属不同的主题,但都是录像这种类型。
抽象工厂可以将一个产品族中的产品(多个产品等级)统一到一起创建。因此在抽象工厂创建时就决定了其包含的产品等级,所以在产品等级需要扩充或修改时,就需要改动抽象工厂,不满足开闭原则。

举例

我们将工厂方法中的例子继续扩展,假如现在需要创建一门课程(产品族),而一门课程必须包含视频(产品等级)和文章(产品等级)两部分。
首先需要定义抽象的课程工厂、视频和文章。

public abstract class CourseFactory {
    public abstract Video getVideo();
    public abstract  Article getArticle();
}
public abstract class Video {
    public abstract void produce();
}
public abstract class Article {
    public abstract void produce();
}

然后根据业务需要和已有的抽象规范,我们可以创建不同的产品。

public class JavaVideo extends Video {
    public void produce() {
        System.out.println("This is Java Video.");
    }
}
public class PythonVideo extends Video {
    public void produce() {
        System.out.println("This is Python Video.");
    }
}
public class JavaArticle extends Article {
    public void produce() {
        System.out.println("This is Java Article.");
    }
}
public class PythonArticle extends Article {
    public void produce() {
        System.out.println("This is Python Article.");
    }
}

对于不同的产品族,我们分别创建不同的工厂。

public class JavaCourseFactory extends CourseFactory {
    public Video getVideo() {
        return new JavaVideo();
    }

    public Article getArticle() {
        return new JavaArticle();
    }
}
public class PythonCourseFactory extends CourseFactory {
    public Video getVideo() {
        return new PythonVideo();
    }

    public Article getArticle() {
        return new PythonArticle();
    }
}

到此,应用层就可以通过不同的创建不同的工厂,直接获取需要的产品,而无需关心和重复编写具体产品的实现细节。

public class Test {
    public static void main(String[] args) {
        CourseFactory courseFactory = new JavaCourseFactory();
        Video video = courseFactory.getVideo();
        video.produce();
        Article article = courseFactory.getArticle();
        article.produce();
    }
}
MyBatis中的抽象工厂

SqlSession是MyBatis工作的核心,MyBatis在创建SqlSession和Configuration对象时,使用的就是抽象工厂,保证了调用者从一个工厂对象中取出的SqlSession和Configuration是配套的。比如MySQL工厂中取出的就是MySQL的SqlSession和Configuration,Oracle工厂中取出的就是Oracle的SqlSession和Configuration。

public interface SqlSessionFactory {
	... ...
    SqlSession openSession(ExecutorType var1, TransactionIsolationLevel var2);
    Configuration getConfiguration();
}

例如实现了SqlSessionFactory接口的DefaultSqlSessionFactory,openSession方法中实际返回了DefaultSqlSession,getConfiguration也会返回对应的配置。应用层也无需关心DefaultSqlSession的复杂实现。

public class DefaultSqlSessionFactory implements SqlSessionFactory {
    private final Configuration configuration;
    public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
        return this.openSessionFromDataSource(execType, level, false);
    }
    private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
        Transaction tx = null;

        DefaultSqlSession var8;
        try {
            Environment environment = this.configuration.getEnvironment();
            TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
            tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
            Executor executor = this.configuration.newExecutor(tx, execType);
            var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
        } catch (Exception var12) {
            this.closeTransaction(tx);
            throw ExceptionFactory.wrapException("Error opening session.  Cause: " + var12, var12);
        } finally {
            ErrorContext.instance().reset();
        }

        return var8;
    }
    public Configuration getConfiguration() {
        return this.configuration;
    }
    ... ... 
}

总结

和工厂方法相比,抽象工厂可以提供成套的、分属不同产品等级的产品。如果一个工厂需要并且可以创建出分属于不同产品等级的统一产品族的产品时,抽象工厂比工厂方法更加简洁且有效率。要分析业务场景是否需要在同一产品族中划分不同产品等级,来决定使用抽象工厂还是工厂方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章