设计模式 | 抽象工厂及相关应用

抽象工厂(Abstract Factory)

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口

抽象工厂是面向产品族的,而工厂方法是面向产品等级结构的,这是两者的主要区别。

适用场景:

  • 客户端不依赖于产品类实例如何被创建、实现等细节
  • 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象时需要大量重复的代码
  • 提供一个产品类的库,所有的产品以同样的接口出现

优缺点

优点:具体产品在应用层代码隔离,无须关心创建细节;将一个系列的产品族统一到一起创建。

缺点:规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。

应用场景

对于一个课程,既包含课程视频,也包含课程笔记:

设计模式 | 抽象工厂及相关应用

抽象视频产品Video:

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

具体视频产品JavaVideoPythonVideo

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课程视频");
    }
}

同样,也有抽象笔记产品Article和具体笔记产品JavaArticlePythonArticle

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

public class JavaArticle extends Artical {
    @Override
    public void produce() {
        System.out.println("编写Java课程手记");
    }
}

public class PythonArticle extends  Artical{
    @Override
    public void produce() {
        System.out.println("编写Python课程手记");
    }
}

课程的抽象工厂CourseFactory,生产视频和笔记两类产品:

public interface CourseFactory {
    Video getVideo();
    Artical getArtical();
}

Java课程的具体工厂JavaCourseFactory

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

    public Artical getArtical() {
        return new JavaArticle();
    }
}

Python课程的具体工厂PythonCourseFactory

public class PythonCourseFactory implements CourseFactory {
    public Video getVideo() {
        return new PythonVideo();
    }

    public Artical getArtical() {
        return new PythonArticle();
    }
}

客户端Test

public class Test {
    public static void main(String[] args) {
        CourseFactory courseFactory = new JavaCourseFactory();
        Video video = courseFactory.getVideo();
        Artical artical = courseFactory.getArtical();
        video.produce();
        artical.produce();
    }
}

可以看出,每一个具体工厂中都只会生产同一产品族下的产品。如果要扩展新的产品族,例如要添加一个算法课程,则添加一个AlgorithmCourseFactory工厂类即可,十分简单;但是如果要增加新的产品等级,比如在课程中除了视频和笔记外还要添加源码,那么就要修改抽象工厂中的实现,并且每一个具体工厂的实现也都要修改,抽象工厂模式在这种场景下就不适用了。

设计模式 | 抽象工厂及相关应用

Connection中的应用

java.sql.Connection接口定义了与指定数据库的连接:

public interface Connection  extends Wrapper, AutoCloseable {
	//...
	Statement createStatement() throws SQLException;
	PreparedStatement prepareStatement(String sql) throws SQLException;
	//...
}

其中,StatementPreparedStatement等也都为接口。我们查看Connection的其中一个实现类ConnectionImpl

public class ConnectionImpl extends ConnectionPropertiesImpl implements Connection {
	//...
	
    public Statement createStatement() throws SQLException {
        return this.createStatement(1003, 1007);
    }

	public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
        this.checkClosed();
        StatementImpl stmt = new StatementImpl(this, this.database);
        stmt.setResultSetType(resultSetType);
        stmt.setResultSetConcurrency(resultSetConcurrency);
        return stmt;
    }
    
    //...
}

createStatement方法中实例化了Statement接口的一个具体实现类,也就是com.mysql.jdbc.StatementImpl

由此可见,在这个场景中Connection相当于一个抽象工厂,而ConnectionImpl是一个具体工厂,抽象产品为Statement,具体产品为StatementImpl。在这个例子中,mysql产品族的工厂只会生产mysql的Statement、PreparedStatement等产品。