UML类图
使用场景
有这样一种应用场景,如一套系统要给两个公式用,但是这两个公司要求的数据库不一样,一个是mysql,另一个是sqlserver,那么如何实现数据库的灵活切换,实现代码的松耦合?抽象工厂模式就是一种不错的选择。抽象工厂模式和工厂模式的区别在于工厂模式只有一种产品,抽象工厂模式有多种类型的产品。
代码实现
public interface UserDao {
public void save();
}
public class UserMysqlDao implements UserDao{
public void save(){
System.out.println("mysql user save");
}
}
public class UserSqlServerDao implements UserDao{
public void save(){
System.out.println("sqlserver user save");
}
}
public interface DepartmentDao {
public void save();
}
public class DepartmentMysqlDao implements DepartmentDao{
public void save(){
System.out.println("mysql department save");
}
}
public class DepartmentSqlserverDao implements DepartmentDao{
public void save(){
System.out.println("sqlserver department save");
}
}
public interface DaoFactory {
public UserDao createUserDao();
public DepartmentDao createDepartmentDao();
}
public class MysqlFactory implements DaoFactory{
@Override
public UserDao createUserDao() {
return new UserMysqlDao();
}
@Override
public DepartmentDao createDepartmentDao() {
return new DepartmentMysqlDao();
}
}
public class SqlserverFactory implements DaoFactory{
@Override
public UserDao createUserDao() {
return new UserSqlServerDao();
}
@Override
public DepartmentDao createDepartmentDao() {
return new DepartmentSqlserverDao();
}
}
public class Main {
public static void main(String[] args) {
//mysql
DaoFactory factory = new MysqlFactory();
UserDao dao = factory.createUserDao();
dao.save();
DepartmentDao dao2 = factory.createDepartmentDao();
dao2.save();
//sqlserver
DaoFactory factory2 = new SqlserverFactory();
UserDao _dao = factory2.createUserDao();
_dao.save();
DepartmentDao _dao2 = factory2.createDepartmentDao();
_dao2.save();
}
}
抽象工厂模式的缺点
抽象工厂模式的缺点是显而易见的,虽然实现了解耦,但是如果要增加一个Dao,需要同时修改很多个类。这里用简单工厂加反射代替实现解耦。
修改工厂类
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;
public class Factory {
Properties prop = new Properties();
public Factory(){
try {
prop.load(Factory.class.getResourceAsStream("config.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}
public UserDao createUserDao(){
try {
Class<?> clazz = Class.forName(prop.getProperty("UserDao"));
Constructor<?> con = clazz.getConstructor(null);
return (UserDao)con.newInstance(null);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException 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();
}
return null;
}
public DepartmentDao createDepartmentDao(){
try {
Class<?> clazz = Class.forName(prop.getProperty("DepartmentDao"));
Constructor<?> con = clazz.getConstructor(null);
return (DepartmentDao)con.newInstance(null);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException 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();
}
return null;
}
}
客户端类
public class Main {
public static void main(String[] args) {
Factory factory = new Factory();
UserDao userDao = factory.createUserDao();
userDao.save();
DepartmentDao departmentDao = factory.createDepartmentDao();
departmentDao.save();
}
}
配置文件config.properties
UserDao=UserMysqlDao
DepartmentDao=DepartmentMysqlDao
以上,无需修改源码,只需在config.properties配置文件中修改成的对应的类即可实现数据库的灵活切换。