时间:2021-07-01 10:21:17 帮助过:5人阅读
由于抽象工厂在我们编程当中经常使用和常见,所有本篇文章对《大话设计模式》中的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; } }简单工厂方这种方式的改进让客户端不再依赖new SqlserverFactory()或new AccessFactory(),而是仅仅依赖于AccesData简单工厂类,让客户端与具体的工厂类解耦。将需要访问的数据库以成员变量的方式声明在AccessData中,修改变量值即可达到切换数据库访问的目的,不需要客户端传给简单工厂中的方法。这样做解决抽象工厂模式的缺点1。 虽然摒弃了IFactory、SqlserverFactory、AccessFactory类。但是我们在新增一个表时会在AccessData类总增加相应的方法。新增一个数据库时需要在每个方法添加case “oracle” 语句。还是没有解决抽象工厂模式的缺点2。
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。 我们发现还有点小瑕疵,我们需要修改DB变量的值类来实现数据库的切换,这样还是需要改动代码,需要重新编译。这个小瑕疵可以使用配置文件来搞定,就是讲DB变量的值从XML文件或properties文件中读取出来。
第15章 就不能换DB吗?—抽象工厂模式
标签: