作为本人《数据库编程》专题的第三篇博文,所讲解的代码,不仅我们要做的窗口所要用到的,而且,与我们未来要学习的一个非常重要的知识点——Java设计模式 有关。
那么,本人先来介绍一下什么是单例、工厂设计模式吧:
单例、工厂设计模式:
首先,什么是“单例”呢?
“单例”就是指某个类只产生了一个实例,并且自行实例化并向整个系统提供这个实例。
那么,如何实现“单例模式”呢?
单例有如下三个要求:
一个单例模式的要求有三点:
- 私有的变量
- 私有的构造方法
- 公有的方法,返回一个实例对象
那么,单例模式有什么优缺点呢?
优点:
- 减少对于内存的消耗;
- 不需要频繁地 创建和销毁对象,缩短时间复杂度
缺点:
- 违背了的单一执行原则
- 忽略了外部关系
- 不适用于变化对象(即接口、抽象类等)
- 滥用单例会出现一些负面问题。如可能会导致池溢出;或是导致对象状态丢失。
本人现在先来给出一个用于存储某个类中 某个方法的全部信息的类,用于辅助之后的两个体现“单例、工厂”设计模式的类:
package com.mec.database.core;
import java.lang.reflect.Field;
/*
* 这个类的作用是:存储某个成员的所有信息
* (存储相应 成员的类型和值 和 其在配置文件中的相应名称(字段名称))
*/
public class Property {
private Field property;
private String column;
public Property() {
}
public Field getProperty() {
return property;
}
public String getPropertyName() {
return property.getName();
}
public Class<?> getType() {
return property.getType();
}
public void setProperty(Field property) {
this.property = property;
}
public String getColumn() {
return column;
}
public void setColumn(String column) {
this.column = column;
}
@Override
public String toString() {
return "成员:" + property.getName() + " <=> 字段:" + column;
}
}
现在,本人来通过底下两个类来展示上面所讲到的“单例、工厂设置模式”:
首先是用于存储某一个类的所有成员的信息的类:
package com.mec.database.core;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*
* 这个类的作用是:存储某个类的全部信息
* (存储 某一类中的所有成员 以及 这个类相应的表的信息)
*
*/
public class TableClassDefinition {
private Class<?> klass; //类
private String table; //对应的表名
private Map<String, Property> propertiesMap; //类中各成员对应表
public TableClassDefinition() {
}
/* 根据 成员对照表 获得 该表中所有成员相应的Property */
public List<Property> columnNameList() {
List<Property> columns = new ArrayList<Property>();
for (String key : propertiesMap.keySet()) {
columns.add(propertiesMap.get(key));
}
return columns;
}
/* 根据上个方法得到的列表,组建SQL语句的部分 */
public String columnList() {
StringBuffer str = new StringBuffer();
boolean first = true;
for (String key : propertiesMap.keySet()) {
Property property = propertiesMap.get(key);
str.append(first ? "" : ",");
str.append(table).append(".").append(property.getColumn());
first = false;
}
return str.toString();
}
/* 将名为className类中的 各成员的名称 和 相应Property对象 存入Map中 */
public void setKlass(String className) {
try {
this.klass = Class.forName(className);
propertiesMap = new HashMap<String, Property>();
Field[] fields = this.klass.getDeclaredFields();
for (Field field : fields) {
String propertyName = field.getName();
Property property = new Property();
property.setProperty(field);
property.setColumn(propertyName);
propertiesMap.put(propertyName, property);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/* 设置指定成员的字段信息 */
public void setColumn(String propertyName, String column) {
Property property = propertiesMap.get(propertyName);
if (property == null) {
return;
}
property.setColumn(column);
}
public String getTable() {
return table;
}
public void setTable(String table) {
this.table = table;
}
public Class<?> getKlass() {
return klass;
}
@Override
public String toString() {
StringBuffer str = new StringBuffer();
str.append("类:" + klass.getName()).append(" <=> 表:") .append(table);
for (String key : propertiesMap.keySet()) {
Property property = propertiesMap.get(key);
if (property == null) {
continue;
}
str.append("\n\t").append(property);
}
return str.toString();
}
现在,本人来介绍下工厂设计模式:
工厂设计模式:
工厂设计模式一共分为三种:
- 简单工厂模式——由 一个抽象产品类 构成
- 工厂方法模式——由 N个具体产品类 构成
- 抽象工厂模式——由 一个工厂类 构成
而这次,本人就来展示下抽象工厂的 使用:
package com.mec.database.core;
import java.util.HashMap;
import java.util.Map;
import com.mec.util.XMLParser;
import org.w3c.dom.Element;
/*
* 这个类的作用是:(存储XML文件中所对应的所有mapping的类的信息)
* 将所有的配置文件中 所有 相应的表的名称 及 类名 存储起来
* */
public class TableClassFactory {
private static final Map<String, TableClassDefinition> tableClassPool;
static {
tableClassPool = new HashMap<String, TableClassDefinition>();
}
public TableClassFactory() {
}
public static void scanTableClassMapping(String xmlPath) {
new XMLParser() {
@Override
public void dealElement(Element element, int index) {
String className = element.getAttribute("class");
String tableName = element.getAttribute("table");
TableClassDefinition tcd = new TableClassDefinition();
tcd.setKlass(className);
tcd.setTable(tableName);
new XMLParser() {
@Override
public void dealElement(Element element, int index) {
String propertyName = element.getAttribute("property");
String columnName = element.getAttribute("name");
tcd.setColumn(propertyName, columnName);
}
}.parseTag(element, "column");
tableClassPool.put(className, tcd);
}
}.parseTag(XMLParser.getDocument(xmlPath), "mapping");
}
public static TableClassDefinition getTableClass(Class<?> klass) {
return getTableClass(klass.getName());
}
public static TableClassDefinition getTableClass(String className) {
return tableClassPool.get(className);
}
}
接下来是用于存储配置文件中存储的所有类的信息的类:
package com.mec.database.core;
import java.util.HashMap;
import java.util.Map;
import com.mec.util.XMLParser;
import org.w3c.dom.Element;
/*
* 这个类的作用是:(存储XML文件中所对应的所有mapping的类的信息)
* 将所有的配置文件中 所有 相应的表的名称 及 类名 存储起来
* */
public class TableClassFactory {
private static final Map<String, TableClassDefinition> tableClassPool;
static {
tableClassPool = new HashMap<String, TableClassDefinition>();
}
public TableClassFactory() {
}
public static void scanTableClassMapping(String xmlPath) {
new XMLParser() {
@Override
public void dealElement(Element element, int index) {
String className = element.getAttribute("class");
String tableName = element.getAttribute("table");
TableClassDefinition tcd = new TableClassDefinition();
tcd.setKlass(className);
tcd.setTable(tableName);
new XMLParser() {
@Override
public void dealElement(Element element, int index) {
String propertyName = element.getAttribute("property");
String columnName = element.getAttribute("name");
tcd.setColumn(propertyName, columnName);
}
}.parseTag(element, "column");
tableClassPool.put(className, tcd);
}
}.parseTag(XMLParser.getDocument(xmlPath), "mapping");
}
public static TableClassDefinition getTableClass(Class<?> klass) {
return getTableClass(klass.getName());
}
public static TableClassDefinition getTableClass(String className) {
return tableClassPool.get(className);
}
}
最后,我们再来编写一个 通过 解析properties文件来驱动数据库,以便我们将数据库所有信息提取出来 的类:
package com.mec.database.core;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import com.mec.util.PropertiesParser;
public class MecDatabase {
private static Connection connection;
public MecDatabase() {
}
/* 驱动数据库 */
public static void loadDatabaseConfig(String configFile)
throws ClassNotFoundException, SQLException {
PropertiesParser propertiesParser = new PropertiesParser();
propertiesParser.loadProperties(configFile);
Class.forName(propertiesParser.value("driver"));
connection = DriverManager.getConnection(propertiesParser.value("url"),
propertiesParser.value("user"),
propertiesParser.value("password"));
}
/* 解析XML配置文件 */
public static void loadOrmMapping(String mappingPath) {
TableClassFactory.scanTableClassMapping(mappingPath);
}
/* 组建SQL语句,并从数据库中提取出信息 */
public <T> List<T> list(Class<?> klass) {
List<T> result = new ArrayList<T>();
StringBuffer str = new StringBuffer("SELECT ");
TableClassDefinition tcd = TableClassFactory.getTableClass(klass);
str.append(tcd.columnList()).append(" ")
.append("FROM ").append(tcd.getTable());
List<Property> propertyList = tcd.columnNameList();
try {
PreparedStatement state = connection.prepareStatement(str.toString());
ResultSet rs = state.executeQuery();
while (rs.next()) {
try {
@SuppressWarnings("unchecked")
T value = (T) klass.newInstance();
for (Property property : propertyList) {
Object obj = rs.getObject(property.getColumn());
setValue(klass, value, property, obj);
}
result.add(value);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
} catch (SQLException e) {
e.printStackTrace();
}
return result;
}
/**
* @param klass 用来进行反射
* @param object 是要完成成员赋值的那个对象
* @param property 反射时所要用到的所有方法的参数的类型集合
* @param value 成员的值
*/
private void setValue(Class<?> klass, Object object, Property property, Object value) { //为Model层的每个model中的每一个成员赋值
String name = property.getPropertyName();
String methodName = "set" + name.substring(0, 1).toUpperCase()
+ name.substring(1);
try {
Method method = klass.getDeclaredMethod(methodName, new Class<?>[] {property.getType()});
method.invoke(object, new Object[] {value});
} catch (Exception e) {
}
}
}
现在同学们看到这里,相信已经发现了,本人之前的博文中,也使用过这个设计思想,所以,好多思想其实在我们的日常代码编写中会有体现,当本人在之后的博文——《Java 程序设计思想》中讲解时,希望同学们不要对此感到畏惧。
那么,我们本专题博文的通过properties文件驱动数据库的操作就实现了,至于接下来的几步操作,将会在本人本专题之后的几篇博文中进行讲解!
如若同学们对于此处的代码有任何不解,请多看几遍,或者在下方的评论区留言。