时间: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吗?—抽象工厂模式
标签: