目录
接着上篇博客,继续… … …
一、抽象工厂模式
工厂模式是设计模式中比较简单的一个设计模式,但很多地方都用到了工厂模式,(如解析xml中,jdbc连接数据库等)利用好工厂模式对程序的设计很有用处。
工厂模式在一些设计模式的书中分为简单工厂模式,工厂方法模式 和 抽象工厂模式 三类。也有把工厂方法模式划分到抽象工厂模式的,认为工厂方法是抽象工厂模式的特例的一种,就是只有一个要实现的产品接口。
1、产品族和产品等级
- 产品族:产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。它们有着共同的接口;举例:一个数据库不同的数据表的集合。
- 产品等级:产品等级结构即产品的继承结构,例如抽象电视机是父类,而具体品牌的电视机是其子类
2、定义
抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。
3、数据访问程序UML
用 抽象工厂模式 的数据访问程序UML。(一切尽在这张UML图里)
抽象工厂模式 支持产品族 的扩展,这里指的是表的扩展,不支持 产品等级,这里指的是数据库访问方式的扩展,即UML图中工厂的扩展。
4、优缺点
1、为新产品族的添加提供了方便,而不为等级结构的增加提供方便。
2、增加产品族,满足开放封闭原则
3、增加产品等级结构(即创建一个新的表),需要修改很多很多(也是,上篇博客最后的遗留问题)
二、用简单工厂改进抽象工厂
去除,三个工厂IFactory,SqlserverFactory,AccessFactory, 取而代之的是DataAccess,用一个简单工厂模式来实现。
1、DataAccess类
package 抽象工厂模式;
public class DataAccess {
private static String db="Sqlserver";
public static IUser CreateUser() {
IUser result =null;
switch(db){
case"Sqlserver":
result=new SqlserverUser();
break;
case"Access":
result=new AccessUser();
break;
}
return result;
}
public static IDepartment CreateDepartment() {
IDepartment result =null;
switch(db){
case"Sqlserver":
result=new SqlserverDepartment();
break;
case"Access":
result=new AccessDepartment();
break;
}
return result;
}
}
在客户端没有出现任何一个SQLserver 或 Access 的字样,达到解耦的目的。但如果想要增加Oracle数据库访问,本来抽象工厂只增级一个OracleFactory工厂类就可以了,现在却要在DataAccess类中每个方法的Switch中增加case了。
三、用反射+抽象工厂实现数据访问程序
在DataAccess1类,用反射技术,取代IFactory、SQLserverFactory和AccessFactory。
与 “用简单工厂改进抽象工厂” 方法唯一的不同是:DataAccess1类!
UML类图:
整体代码结构:
1、DataAccess1类:
package 抽象工厂模式;
//不在再使用switch-case语句
public class DataAccess1 {
private static String AssemblyName="抽象工厂模式";
private static String db="Sqlserver";
public static IUser CreateUser() throws InstantiationException, IllegalAccessException, ClassNotFoundException{
String className=AssemblyName+"."+db+"User";
return (IUser)Class.forName(className).newInstance();
}
public static IDepartment CreateDepartment() throws InstantiationException, IllegalAccessException, ClassNotFoundException{
String className=AssemblyName+"."+db+"Department";
return (IDepartment)Class.forName(className).newInstance();
}
}
2、IDepartment接口
package 抽象工厂模式;
public interface IDepartment {
public void Insert(Department department);
public Department GetDepartment(int id);
}
3、AccessIDepartment、SqlserverDepartment 实现 IDepartment 接口
package 抽象工厂模式;
public class AccessDepartment implements IDepartment {
@Override
public void Insert(Department department) {
System.out.println("在 Access 中给Department表增加一条记录。");
}
@Override
public Department GetDepartment(int id) {
System.out.println("在Access 中根据ID得到Department表一条记录");
return null;
}
}
package 抽象工厂模式;
public class SqlserverDepartment implements IDepartment {
@Override
public void Insert(Department department) {
System.out.println("在 SQL Server中给Department表增加一条记录。");
}
@Override
public Department GetDepartment(int id) {
System.out.println("在SQL Server中根据ID得到Department表一条记录");
return null;
}
}
4、IUser接口
IUser接口
package 抽象工厂模式;
public interface IUser {
public void Insert(User user);
public User GetUser(int id);
}
附加User普通类
package 抽象工厂模式;
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;
}
}
5、AccessUser,SqlserverUser 实现接口IUser
package 抽象工厂模式;
public class AccessUser implements IUser {
@Override
public void Insert(User user) {
System.out.println("在 Access 中给User表增加一条记录。");
}
@Override
public User GetUser(int id) {
System.out.println("在Access 中根据ID得到Access表一条记录");
return null;
}
}
package 抽象工厂模式;
public class SqlserverUser implements IUser {
@Override
public void Insert(User user) {
System.out.println("在 SQL Server中给User表增加一条记录。");
}
@Override
public User GetUser(int id) {
System.out.println("在SQL Server中根据ID得到User表一条记录");
return null;
}
}
6、Test客户端
package 抽象工厂模式;
import org.dom4j.DocumentException;
public class Test {
public static void main(String[] args) throws IllegalAccessException, DocumentException,InstantiationException, ClassNotFoundException {
User user = new User();
Department dept = new Department();
IUser iu = DataAccess1.CreateUser();
iu.Insert(user);
iu.GetUser(1);
IDepartment id = DataAccess1.CreateDepartment() ;
id.Insert(dept);
id.GetDepartment(1);
}
}
7、运行结果
四、反射+配置文件实现数据访问程序
代码整体:
1、XML配置文件
<?xml version="1.0" encoding="UTF-8"?>
<databases>
<database>
<name>Access</name>
</database>
</databases>
2、DataAccess类
package 抽象工厂模式;
import java.io.File;
import java.util.Iterator;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class DataAccess {
public static String getDb() throws DocumentException{
SAXReader reader = new SAXReader();//创建解析器
//Object obj=null;
//获取Document对象
Document doc=reader.read(new File("src/com5_10.xml"));
//获取xIterator<Element> it = root.elementIterator();根结点
Element root=doc.getRootElement();
//获取根元素所有子元素
@SuppressWarnings("unchecked")
Iterator<Element> it =root.elementIterator();
//取出元素
Element e=it.next();
String name=e.element("name").getStringValue();
return name;
}
// public static void show() throws DocumentException{
// System.out.println(getDb());
// }
public static IUser CreateUser() throws ClassNotFoundException, InstantiationException, IllegalAccessException, DocumentException
{
String db=getDb();
return (IUser)Class.forName("抽象工厂模式."+db+"User").newInstance();
}
public static IDepartment CreateDepartment() throws ClassNotFoundException, InstantiationException, IllegalAccessException, DocumentException {
String db=getDb();
return (IDepartment)Class.forName("抽象工厂模式."+db+"Department").newInstance();
}
}
3、Test客户端
package 抽象工厂模式;
import org.dom4j.DocumentException;
public class Test {
public static void main(String[] args) throws IllegalAccessException, DocumentException,InstantiationException, ClassNotFoundException {
User user = new User();
Department dept = new Department();
IUser iu = DataAccess.CreateUser();
iu.Insert(user);
iu.GetUser(1);
IDepartment id = DataAccess.CreateDepartment() ;
id.Insert(dept);
id.GetDepartment(1);
// DataAccess.show();
}
}