抽象工厂模式
抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
结构图
代码实现
两种抽象产品类:A和B
/**
* 抽象产品A
*
* @author xukai 2016年3月20日 下午1:47:24
*/
public abstract class AbstractProductA {
}
/**
* 抽象产品B
*
* @author xukai 2016年3月20日 下午1:47:46
*/
public abstract class AbstractProductB {
}
产品类A下的具体产品:
/**
* A的具体产品1
* @author xukai
* 2016年3月20日 下午1:51:04
*/
public class ProductA1 extends AbstractProductA {
@Override
public String toString() {
return "ProductA1";
}
}
/**
* A的具体产品2
* @author xukai
* 2016年3月20日 下午1:52:12
*/
public class ProductA2 extends AbstractProductA {
@Override
public String toString() {
return "ProductA2";
}
}
产品类B下的具体产品:
/**
* B的具体产品1
* @author xukai
* 2016年3月20日 下午1:53:14
*/
public class ProductB1 extends AbstractProductB {
@Override
public String toString() {
return "ProductB1";
}
}
/**
* B的具体产品2
* @author xukai
* 2016年3月20日 下午1:53:44
*/
public class ProductB2 extends AbstractProductB {
@Override
public String toString() {
return "ProductB2";
}
}
抽象工厂类:包含所有产品创建的抽象方法
/**
* 抽象工厂接口,产品关键的抽象方法
* @author xukai
* 2016年3月20日 下午1:46:27
*/
public interface AbstractFactory {
public abstract AbstractProductA createProductA();
public abstract AbstractProductB createProductB();
}
具体工厂:生产具体的产品
/**
* 具体工厂,创建具体产品
* @author xukai
* 2016年3月20日 下午1:54:37
*/
public class ConcreteFactory1 implements AbstractFactory{
@Override
public AbstractProductA createProductA() {
return new ProductA1();
}
@Override
public AbstractProductB createProductB() {
return new ProductB1();
}
}
/**
* 具体工厂,创建具体产品
* @author xukai
* 2016年3月20日 下午1:55:24
*/
public class ConcreteFactory2 implements AbstractFactory {
@Override
public AbstractProductA createProductA() {
return new ProductA2();
}
@Override
public AbstractProductB createProductB() {
return new ProductB2();
}
}
客户端:
public class Client {
public static void main(String[] args) {
AbstractFactory factory = new ConcreteFactory1();
System.out.println(factory.createProductA() + "," + factory.createProductB());
factory = new ConcreteFactory2();
System.out.println(factory.createProductA() + "," + factory.createProductB());
}
}
控制台输出:
ProductA1,ProductB1
ProductA2,ProductB2
实例对应,如下图中的汽车制造
*两厢车和三厢车称为不同的等级结构,2.0排量两厢和2.0排量三厢称为不同的产品簇
抽象工厂和工厂方法区别:一个产品等级结构为工厂方法模式,两个或两个以上产品等级结构为抽象工厂模式。
demo
问题:实际Web开发中,经常换数据库(DB)解决Oracle和MySQL直接数据的切换问题UML类图
代码实现
User和Department接口:
public interface IUser {
}
public interface IDepartment {
}
对应不同数据库实体类
MySQL:
public class MysqlDepartment implements IDepartment {
}
public class MysqlUser implements IUser {
}
Oracle:
public class OracleUser implements IUser {
}
public class OracleDepartment implements IDepartment {
}
抽象工厂:
public interface IFactory {
public void createUser();
public void createDepartment();
public IUser getUser();
public IDepartment getDepartment();
}
具体工厂:
public class OracleFactory implements IFactory {
@Override
public void createUser() {
System.out.println("oracle 插入user语法");
}
@Override
public void createDepartment() {
System.out.println("oracle 插入department语法");
}
@Override
public IUser getUser() {
return new OracleUser();
}
@Override
public IDepartment getDepartment() {
return new OracleDepartment();
}
}
public class MysqlFactory implements IFactory {
@Override
public void createUser() {
System.out.println("mysql 插入user语法");
}
@Override
public void createDepartment() {
System.out.println("mysql 插入department语法");
}
@Override
public IUser getUser() {
return new MysqlUser();
}
@Override
public IDepartment getDepartment() {
return new MysqlDepartment();
}
}
客户端:
public class Client {
public static void main(String[] args) {
IFactory facotry = new MysqlFactory();
facotry.createUser();
facotry.createDepartment();
System.out.println(facotry.getUser());
System.out.println(facotry.getDepartment());
facotry = new OracleFactory();
facotry.createUser();
facotry.createDepartment();
System.out.println(facotry.getUser());
System.out.println(facotry.getDepartment());
}
}
控制台输出:
mysql 插入user语法
mysql 插入department语法
com.edu.demo.MysqlUser@28d76d1e
com.edu.demo.MysqlDepartment@2ce62a39
oracle 插入user语法
oracle 插入department语法
com.edu.demo.OracleUser@6cd8f317
com.edu.demo.OracleDepartment@4e2c390c
可以从客户端中看出,需要什么类型的产品就创建什么类型的具体工厂。(如果这里只操作一张数据库表,如:user表,那么就是工厂方法模式)
抽象工厂模式的优点和缺点
优点:方便交换产品系列,想要实现这步操作,只需要改变具体工厂即可。
缺点:假如在上面的demo中,添加一张数据库表,那么至少要增加三个类,如:product表,需要IProduct、MysqlProduct、OracleProduct等。另外还需要修改其他的具体工厂类。
**使用工厂模式,只需要关心降低耦合的的目的是否达到**
简单工厂+反射
解决上面的缺点
UML图:
思路:通过反射,修改DataAccess中的db属性,从而判断返回哪种类型的具体类。
代码实现
public class DataAccess {
private static String db = null;
public DataAccess() {
System.out.println("调用构造方法");
}
public IUser createUser(){
IUser user = null;
switch (db) {
case "Oracle":
user = new OracleUser();
break;
case "Mysql":
user = new MysqlUser();
break;
}
return user;
}
public IDepartment createDepartment(){
IDepartment department = null;
switch (db) {
case "Oracle":
department = new OracleDepartment();
break;
case "Mysql":
department = new MysqlDepartment();
break;
}
return department;
}
@Override
public String toString() {
return "DataAccess [" + db + "]";
}
}
客户端使用反射操作:
public class Client {
public static void main(String[] args) {
Class<?> c1 = null; // 类
Object access = null; // DataAccess对象
Field fs = null; // 属性
Method[] method = null; // 所有方法
try {
c1 = Class.forName("com.edu.DataAccess");
fs = c1.getDeclaredField("db");
access = c1.newInstance(); // 调用空参构造方法
fs.setAccessible(true); // 设置可修改
fs.set(access, "Oracle"); // db = "Oracle"
method = c1.getDeclaredMethods();
Object o = null;
for (int i = 0; i < method.length; i++) {
if (method[i].getName().equals("createUser")
|| method[i].getName().equals("createDepartment")) {
o = method[i].invoke(access, null); // 执行类中方法
System.out.println(o);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
控制台输出:
调用构造方法
com.edu.OracleUser@7d9331eb
com.edu.OracleDepartment@52ecba8