由于抽象工厂在我们编程当中经常使用和常见,所有本篇文章对《大话设计模式》中的15章做了很详细的比较。通过一个Dao层可以更换访问任意数据库的例子来学习抽象工厂模式。例如:Dao层可以访问Sqlserver数据库,也可以访问Access数据库,当程序新增访问Oracle数据库时,无需修改现有代码,只需要添加访问Oracle相关的类就可以,实现了开闭原则。本篇文章的例子中每种数据库上都有User和Department表,我们Dao层对这两个表进行查询和插入操作。
一下是访问Sqlserver数据库的代码。
public class User { private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
public class SqlserverUser{ public void insert(User user) { System.out.println("SqlserverUser insert user"); } public void getUser(int id) { System.out.println("SqlserverUser get user"); } }
public class ClientTest { public static void main(String [] args){ SqlserverUser su = new SqlserverUser(); su.getUser(1); su.insert(new User()); } }
public interface IUser { void insert(User user); void getUser(int id); }
public class SqlserverUser implements IUser { @Override public void insert(User user) { System.out.println("SqlserverUser insert user"); } @Override public void getUser(int id) { System.out.println("SqlserverUser get user"); } }
public class AccessUser implements IUser { @Override public void insert(User user) { System.out.println("AccessUser insert user"); } @Override public void getUser(int id) { System.out.println("AccessUser get user"); } }
public interface IFactory { IUser createUser(); }
public class SqlserverFacotry implements IFactory { @Override public IUser createUser() { // TODO Auto-generated method stub return new SqlserverUser(); } }
public class AccessFactory implements IFactory { @Override public IUser createUser() { // TODO Auto-generated method stub return new AccessUser(); } }
public class ClientTest { public static void main(String [] args){ IFactory factory = new SqlserverFacotry(); //IFactory factory = new AccessFactory(); IUser iu = factory.createUser(); iu.insert(new User()); iu.getUser(1); } }
public class DataAccess { private static String DB = "sqlserver"; public static IUser createUser(){ IUser user = null; switch (DB) { case "sqlserver": user = new SqlserverUser(); break; case "access": user = new AccessUser(); break; } return user; } public static IDepartment createDepartment(){ IDepartment dep = null; switch (DB) { case "sqlserver": dep = new SqlserverDepartment(); break; case "access": dep = new AccessDepartment(); break; } return dep; } }
public class DataAccess { private static String DB = "sqlserver"; public static IUser createUser(){ IUser user = null; switch (DB) { case "sqlserver": user = new SqlserverUser(); break; case "access": user = new AccessUser(); break; } return user; } public static IDepartment createDepartment(){ IDepartment dep = null; switch (DB) { case "sqlserver": dep = new SqlserverDepartment(); break; case "access": dep = new AccessDepartment(); break; } return dep; } }
package fly.zxy.dhms.chapter15_8.factory; import fly.zxy.dhms.chapter15_8.IDB.IDepartment; import fly.zxy.dhms.chapter15_8.IDB.IUser; public class DataAccess { private static String DB = "sqlserver"; private static String packageBasePath = "fly.zxy.dhms.chapter15_8"; public static IUser createUser(){ String name = "User"; IUser iu =null; iu = (IUser) ref( getPackagePath(name) ); return iu; } public static IDepartment createDepartment(){ String name = "Department"; IDepartment dep = null; dep = (IDepartment) ref( getPackagePath(name) ); return dep; } private static String getPackagePath(String className){ //fly.zxy.dhms.chapter15_8.sqlserverDB //fly.zxy.dhms.chapter15_8.accessDB className = DB.substring(0,1).toUpperCase() + DB.substring(1, DB.length()) + className; String path = packageBasePath+"."+DB+"DB"+"."+className; return path; } private static Object ref(String className){ Object obj = null; try { Class<? extends Object> cls = Class.forName(className); obj = cls.newInstance(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } return obj; } }由于使用了反射技术,我们在增加表的时候只需要在AccessData类中增加对应的方法,而方法中没有了一堆的switch case分支判断。新增对一种数据库的访问,无需再更改每个方法增加case语句了。解决了抽象工厂模式的缺点二。其实从某种角度来说,所有在使用简单工厂的地方,都可以考虑用反射来去除switch或if。