工厂方法模式中的每个具体工厂只有一个或者一组重载的工厂方法,只能生产一种产品,可能会导致系统中存在大量的工厂类,会增加系统的开销。有时候需要工厂可以提供多种产品对象,而不是单一的产品对象。例如一个电器工厂,它可以生产电视、电冰箱、洗衣机、空调之类的。这时候就可以将一些相关产品组成一个产品族,由一个工厂来统一生产。
产品等级结构
即产品的继承结构,如一个抽象类是电视机,其子类包括海尔电视机、海信电视机、TCL电视机。
产品族
指同一个工厂生产的位于不同产品等级结构中的一组产品。如海尔电器工厂生产海尔电视机、海尔冰箱。海尔冰箱和海尔电视机就构成一个产品族。
抽象工厂模式概述
当系统所以提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。工厂方法模式针对的是一个产品等级结构,抽象工厂模式需要面对多个产品等级结构。
定义
提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。
结构
AbstractFactory(抽象工厂)
它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。
ConcreteFactory(具体工厂)
实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成一个产品族,每一个产品都位于某个产品等级结构中。
AbstractProduct(抽象产品)
它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
ConcreteProduct(具体产品)
它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
应用实例 - 数据库操作
/**
*
* @ClassName connect
* @Description 数据库连接接口 - 抽象产品
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public interface Connection {
void connect();
}
/**
*
* @ClassName OracleConnection
* @Description Oracle数据库连接类 - 具体产品
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public class OracleConnection implements Connection {
@Override
public void connect() {
System.out.println("连接Oracle数据");
}
}
/**
*
* @ClassName MySQLConnection
* @Description MySQL数据库连接类 - 具体产品
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public class MySQLConnection implements Connection {
@Override
public void connect() {
System.out.println("连接MySQL数据库");
}
}
/**
*
* @ClassName Statement
* @Description 数据库语句 - 抽象产品
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public interface Statement {
void executeStatement();
}
/**
*
* @ClassName OracleStatement
* @Description Oracle数据库语句类 - 具体产品
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public class OracleStatement implements Statement {
@Override
public void executeStatement() {
System.out.println("执行Oracle数据库语句");
}
}
/**
*
* @ClassName MySQLStatement
* @Description MySQL数据库语句类 - 具体产品
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public class MySQLStatement implements Statement {
@Override
public void executeStatement() {
System.out.println("执行MySQL数据库语句");
}
}
/**
*
* @ClassName DBFactory
* @Description 数据库工厂接口 - 抽象工厂
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public interface DBFactory {
Connection createConnection();
Statement createStatement();
}
/**
*
* @ClassName OracleFactory
* @Description Oracle数据库工厂 - 具体工厂
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public class OracleFactory implements DBFactory {
@Override
public Connection createConnection() {
return new OracleConnection();
}
@Override
public Statement createStatement() {
return new OracleStatement();
}
}
/**
*
* @ClassName MySQLFactory
* @Description MySQL数据库工厂 - 具体工厂
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public class MySQLFactory implements DBFactory {
@Override
public Connection createConnection() {
return new MySQLConnection();
}
@Override
public Statement createStatement() {
return new MySQLStatement();
}
}
/**
*
* @ClassName Client
* @Description 客户端测试类
* @Author 柳成荫
* @Date 2019年9月21日
* @Version V1.0.0
*/
public class Client {
public static void main(String[] args) {
DBFactory dbFactory;
Connection connection;
Statement statement;
dbFactory = new OracleFactory();
connection = dbFactory.createConnection();
statement = dbFactory.createStatement();
connection.connect();
statement.executeStatement();
}
}
优点
1.隔离了具体类的生成,使得客户端并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需要改变具体工厂的实例就可以在某种程度上改变整个软件系统的行为。
2.当一个产品族中有多个对象被设计在一起工作时,它能够保证客户端始终只使用同一个产品族的对象。
3.增加新的产品族很方便,无需修改已有系统,符合开闭原则。
缺点
增加新的产品等级结构麻烦,需要对原有系统进行较大修改,甚至需要修改抽象层代码,违背开闭原则。