MVC模式的初体验
在这里要说到MVC模式,其实事实上就是model(数据) view (视图)control(控制)这三方面的解耦与融合,在代码阶层即是各司其职,但又相互合作,巧妙结合的一种工具开发模式。从这个方面引出我今天想要说的 内容: (MVC中的model 和 view 部分的解耦与融合,并且说一些关于properties解析与Dao层之间相互联系的小技巧) ,我以一个简单的学生管理系统为例进行问题的说明。
对于一个学生信息管理系统来说,我们最先开始的是设计界面即 (view),然后是对界面中的控件的相应的内容进行初始化,之后就是一系列的对输入数据的操作,对数据的保存,显示等等(操作这部分暂时不做说明,主要说 model 和 view )。
关于学生信息的所有控件内容组合在一起事实上就是一个学生的完整信息,即一个学生信息的类,studentMessageModel ( 也就是所谓的 Model(数据) ),单个的学生信息需要保存,那么每一个学生的信息事实上对应一个studentMessageModel类的对象。那对于其他的控件例如民族,籍贯,专业等等其实也都对应着 nativeModel类,nationModel类 等等,因为这些民族,籍贯等等需要我们进行其内容的初始化,当我们初始化的时候我们就需要有对应的 model类的对象的list集合 来初始化这些控件,那么问题就出来了,这些 List 的内容从何而来?并且怎样能够将获取这些 list 的代码能够独立出来并且和 view(视图) 部分代码完美的结合呢?
基本视图
下面 我们以一个控件(民族下拉框选择 native)为例进行问题的说明与解释。下拉框出现的内容是不同的民族,这些信息在数据库中,我们数据库中的native表中有两个字段(id name), id是不同民族的编号,name是不同民族的名字。nativeModel类中有两个成员(id name)。上边说到,其实每一个控件对应一个model类,我们使用这些model类的对象的集合去初始化这些控件,我们的目的是通过与数据库建立连接,然后从表中获得数据形成model类的对象的集合,然后结合view(视图)初始化控件,并且完成上边我们说的各司其职,并且互相结合。
那对于在 视图部分 ( 即界面部分的代码)我们希望出现的是如下情况 : 我们不用考虑怎样去实现获取初始化控件的model类的对象的集合,我们只需在这部分代码直接进行使用nativeDao类中的getNativeList() ,这就实现了最基础的一步,view只实现对控件的初始化,而数据的来源由Dao层的nativeDao类来进行产生。
[ studentView类(view) ]
public class studentView {
public studentView() {
initilize();
reinitilize();
dealAction();
}
public void initilize() {
//界面的初始化,就是画一个界面的过程。
//确定各种控件的位置大小
//这部分极为简单,不用多叙述
}
public void reinitilize() {//这部分主要数对控件具体内容的初始化,下拉框选项内容的填充等等
List<nativeModel> nativeList =nativeDao.getNativeList();
//nativeDao是Dao层中的一个类,getNativeList()是这个类中的一个静态方法,采用sql语句
//从数据库的native表中将每一条记录形成一个nativeModel的对象,然后返回nativeModel的对象集合
//然后对控件进行初始化
jcbNative.removeAllItems();
//jcbNative是民族下拉控件
for(nativeModel one : nativeList) {
jcbNative.addItem(one);
}
public void dealAction() {
//处理相关的响应
//对点击操作的响应等等
}
public void showWindow() {
//显示窗口
}
List < nativeModel> nativeList = nativeDao.getNativeList();
nativeDao类中的一个方法 getNativeList() 用来提供给一个可以用来初始化控件的 modelList。那么Dao层便被提到,Dao层事实上就是数据库访问层,通过访问数据库而得到对应的数据。我们最先想到的代码应该是这样,在Dao层直接提供一个nativeDao类,类中有一个方法采用sql语句从数据库中获得数据产生modelList进行返回,并且在这个类中我们还必须进行connection的链接,作为访问数据库的基础。那么我们的这个类中最起码要写两部分的内容,一个是关于数据库的链接部分代码,再一个就是采用sql语句产生一个 modelList 的方法。如果每一个像这样需要访问数据库的类都要写关于与数据库链接的代码,那么在程序的一次运行中每new一次都会对数据库进行一次链接,为了不频繁的对数据库进行链接,我么采用一个dataBase的类来处理以数据库的链接问题,那么对于上述的操作我们可以采用如下代码实现:
database类
public class database {
private static Connection connection;
public database() {
}
public static void loadProperties(String path) {
properParser.deposit(path);
}
public static Connection getConnection() {//在这个类运行的时候已经执行
if (connection == null) {//如果在一此运行的过程中,进行多次链接,那么只需进行一次连接,之后的链接操作直接是return connection
try {
Class.forName(properParser.getValue("driver"));
connection = DriverManager.getConnection(
properParser.getValue("url"),
properParser.getValue("user"),
properParser.getValue("password"));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
}
return connection;
}
public ResultSet executeQuery(String sql) {
ResultSet rs = null;
Connection connection = getConnection();
try {
rs = connection.prepareStatement(sql).executeQuery();
return rs;
} catch (SQLException e) {
e.printStackTrace();
}
return rs;
}
}
nativeDao类
public class nativeDao {
//通过数据库来获取数据
static {
database.loadProperties("/database.cfg.properties");
}
public List<nativeModel> getNativeList() {
String sql = "SELECT id,name FROM sys_native_cnst";
List<nativeModel> nativeList = new ArrayList<>();
database db = new database();
ResultSet rs = db.executeQuery(sql);
try {
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
nativeList.add(new nativeInfo(id,name));
}
} catch (SQLException e) {
e.printStackTrace();
}
return nativeList
}
}
上面这两部分代码事实上是nativeDao类中调用database中的静态方法,实现了nativeDao类想要实现的功能(即数据库链接以及访问数据库产生对应的modelList),并且采用database类单独connection的好处在于,对于其他的xxxDao类,例如nationDao类,想到从数据库获取到籍贯的modelList事实上也需要链接数据库,而在这时候就可以直接使用database中的静态方法,不用再重复写关于链接数据库部分的代码了。
在这里作一个小结,对于Dao层我们。现在已经很明确了,就是用来访问数据库的,但这里有一小技巧是,Dao层既然是用来访问数据库的 (说白了就是采用sql语句访问), 那当然也只是独立的访问数据库,而不去关心底层的数据库是Oracle 还是 MS SQL Server等等其他的数据库。只需要database类来完成不同数据库的里链接以便Dao层进行访问,可以采用配置文件的方式来实现针对不同数据库的链接,通过采用properties解析工具对文件进行解析来进行不同数据库的链接,通过properties解析工具将文件的内容可以根据键值对的关系存储在一个hashmap中,这样也是为了能够减少对文件的访问操作,直接将这些数据放入内存,提高效率。
properties配置文件
properties解析工具 即 proparser类
public class properParser {
//这个类的目标是为了减少对于硬盘的访问次数,用空间换区时间
//将文件中的键值对搞到hashMap中相当于存储在内存中,以便访问
//对于不同文件的的来说,可以将不同文件中的键值对儿,放在一个Hashmap中,
private static final Map<String,String> messageMap = new HashMap<>();
public properParser() {
}
public static void deposit(String path) {
Properties proper = new Properties();
InputStream is = properParser.class.getResourceAsStream(path);
try {
proper.load(is);
} catch (IOException e) {
e.printStackTrace();
}
Enumeration<Object> keySet = proper.keys();
while(keySet.hasMoreElements()) {
String key = (String)keySet.nextElement();
String value = proper.getProperty(key);
messageMap.put(key, value);
}
}
}
至此我们已经完成了操作就是通过采用Dao层与properties解析工具和配置文件,解决了从表中获取数据并且通过 Dao层 中的类来产生可以初始化界面控件的的问题,解决了各司其职,并且能够互相结合的效果。到这里的代码还是有一些不完美的问题所在,那就是 Dao层 中的 xxxDao类 虽然可以通过访问数据库得到对应的 modelList,但获取不同 modelList 的方法需要些不同的sql语句,如果 Dao层 有很多获取不同 modelList 的类,那我们就需要写重复的代码,重复的部分如下:
public List<nativeModel> getNativeList() {
sql = "SELECT id,name FROM sys_native_cnst";
List<nativeModel> nativeList = new ArrayList<>();
database db = new database();
ResultSet rs = db.executeQuery(sql);
try {
while(rs.next()) {
String id = rs.getString("id");
String name = rs.getString("name");
nativeList.add(new nativeInfo(id,name));
}
} catch (SQLException e) {
e.printStackTrace();
}
return nativeList
}
}
为什么说这是重复的部分呢,原因是这段代码其实是Dao层中的一个nativeDao类中的一个方法,用来从数据库的 native表 中获取每一条记录形成 nativeModel 的对象的 List,从而结合 视图(view) 完成对 nativel控件 的初始化,那么对于其他的控件,例如nation(籍贯)我们需nationDao这样的类拥有一个方法并且这个方法有重复上述的代码进行获取nationModel这样的信息,我们只需要对上述的代码进行表名称的更改,字段名称的更改,并且将List< nativelModel > 改为list< nationModel >就可以完成 nationDao 这个类中的方法。那这样就出现了像上边这些代码大体相同的代码,而我们要做的就是对这样的情况进行再次优化。
优化内容:
对于不同的xxxModel我们可以做出一套工具自动生成sql语句并且产生相关的 modelList数据,相当于把上边的代码变为一个工具,根据不同的 xxxmodel类,我们可以直接采用工具获取对应的modelList,然后再在 xxxDao类 中的方法直接用这个工具就好, 那么接下来优化的问题就牵扯到我在 标题: 反射机制 xml解析 与Dao层的结合使用 文章中具体说明。
ps: 以上内容实属个人观念,如有不足地方,请各位大神指点