数据库编程(3)—— core层设计 与 浅谈 单例设计模式

作为本人《数据库编程》专题的第三篇博文,所讲解的代码,不仅我们要做的窗口所要用到的,而且,与我们未来要学习的一个非常重要的知识点——Java设计模式 有关。

那么,本人先来介绍一下什么是单例、工厂设计模式吧:

单例、工厂设计模式:

首先,什么是“单例”呢?

“单例”就是指某个类只产生了一个实例,并且自行实例化并向整个系统提供这个实例。

那么,如何实现“单例模式”呢?

单例有如下三个要求:
一个单例模式的要求有三点:

  1. 私有的变量
  2. 私有的构造方法
  3. 公有的方法,返回一个实例对象

那么,单例模式有什么优缺点呢?
优点

  1. 减少对于内存的消耗;
  2. 不需要频繁地 创建和销毁对象,缩短时间复杂度

缺点

  1. 违背了的单一执行原则
  2. 忽略了外部关系
  3. 不适用于变化对象(即接口、抽象类等)
  4. 滥用单例会出现一些负面问题。如可能会导致池溢出;或是导致对象状态丢失。

本人现在先来给出一个用于存储某个类中 某个方法的全部信息的类,用于辅助之后的两个体现“单例、工厂”设计模式的类:

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();
	}

现在,本人来介绍下工厂设计模式:
工厂设计模式
工厂设计模式一共分为三种:

  1. 简单工厂模式——由 一个抽象产品类 构成
  2. 工厂方法模式——由 N个具体产品类 构成
  3. 抽象工厂模式——由 一个工厂类 构成

而这次,本人就来展示下抽象工厂的 使用:

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文件驱动数据库的操作就实现了,至于接下来的几步操作,将会在本人本专题之后的几篇博文中进行讲解!

如若同学们对于此处的代码有任何不解,请多看几遍,或者在下方的评论区留言。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值