基于OOP原则优化
原因:在程序中只要有哪个程序功能需要对数据库进行访问操作,那么必须要有之前学习的四个步骤:(创建数据库连接对象-创建数据库命令对象-针对不同的命令执行结果是否选择使用另外两个对象对结果进行处理)
因此:决定使用面向对象的原则对数据库的访问操作功能进行单独提取
通用数据访问类
实现代码的复用
-
代码复用的基本形式:编写一个通用的方法
-
代码复用技术的要求:
-
原则:提取不变的,封装改变的
-
技巧:不变的作为“方法体”,变化的作为方法的“参数”。
-
DBHelper/SQLHelper类的封装
/// <summary>
/// 数据库访问操作类,该对象中提供了对数据库进行各种操作(增、删、改、查)的方法
/// </summary>
class SQLHelper
{
static string con = "Server=.;DataBase=InLettDB;UID=sa;Pwd=123;";
/// <summary>
/// 该方法可以对SQL语句执行完成之后返回结果为受影响行数的SQL语句进行命令执行(增加、删除、修改数据操作);
/// </summary>
/// <param name="sql">要执行的SQL语句</param>
/// <returns></returns>
public static int ExecuteNonQuery(string sql)
{
SqlConnection sqlCon = new SqlConnection(con);
SqlCommand cmd = new SqlCommand(sql, sqlCon);
sqlCon.Open();
int res = cmd.ExecuteNonQuery();
sqlCon.Close();
return res;
}
/// <summary>
/// 该方法可以对SQL语句执行完成之后返回结果中的首行首列数据,适用于SQL语句查询单一结果值
/// </summary>
/// <param name="sql">查询的SQL语句</param>
/// <returns></returns>
public static object ExecuteScalar(string sql)
{
SqlConnection sqlCon = new SqlConnection(con);
SqlCommand cmd = new SqlCommand(sql, sqlCon);
sqlCon.Open();
object res = cmd.ExecuteScalar();
sqlCon.Close();
return res;
}
}
基于对象职责明确原则优化
回顾之前的代码:数据展示代码和数据库访问代码混杂编写在一起
面向对象的基本原则:
-
单一职责原则(对象职责明确原则)
要求:一个对象只需要做好一件事情,必须专注,职责过多容易引起变化的原因就越多,程序就不稳定(高内聚,低耦合)
-
开放封闭原则(核心原则)
要求:需要变化时尽量少的修改类的设计,而是通过扩展类来完成。即封闭修改,开放扩展
-
依赖倒置原则(OOP精髓)
要求:基于接口编程,高层模块调用接口,底层模块实现接口,防止底层变化直接影响高层
-
接口隔离原则
要求:尽可能多的使用专用的小接口,而不是总接口,避免接口过于复杂
-
里氏替换原则
要求:在继承关系子类可以替换父类,虚拟机可以根据父类变量动态的找到具体的子类对象,从而实现子类
问题分析与解决
前后台代码混编的缺点
-
程序编写人员必须非常熟悉后台数据的设计
-
业务逻辑负责时很难查找错误,并且不利于后期的维护
-
不符合面向对象的设计思想-》违反对象职责明确原则
解决方案
-
将数据展示代码和数据访问代码进行分离
-
根据当前需要访问的后台实体,创建一个对应的数据访问类
-
将该实体操作的方法封装到对应的数据访问类型
对象职责明确原则总结
原则
分离“界面代码”和“数据访问代码”
好处
-
不管是什么类型的应用程序(Winform/WPF/WebForm/...)当界面法生变化的时候,数据访问部分一般不需要任何改变
-
同时前台设计人员和后台编写人员可以很好的分离
注意
当写程序时,界面中不能出现任何SQL语句,数据访问后台代码中也不应该有其他的业务逻辑代码
扩展
对象职责明确原则对后续“三层架构”、“工厂模式”、“MVC模式”...打下基础
OOP实体对象优化
为什么要使用实体对象
方法参数多的缺点
-
定义和使用不方便,很容易把参数写错
-
当对象的属性变化时,方法的参数必须改变
-
参数的改变,造成对象接口不稳定,降低了可维护性、可扩展性和安全性,与面向对象设计原则相悖
-
不符合面向对象中“低耦合,高内聚”的要求
-
后台方法编写依赖数据库完成
-
前台代码实现依赖后台代码方法的完成,团队中无法并行开发
问题解决思路
-
为类的设计提供一个规范,稳定对象的接口
-
不同开发人员只需要按照规范接口即可同步开发
问题解决办法
使用“实体类”作为方法参数,稳定对外接口
实体类的设计
概念
-
只包含属性和构造方法的类称为实体类
-
实体类属性和数据库实体属性一一对应(实体类中的属性和数据表中的字段的名称和数据类型保持一致)
数据库中有多少张表,程序中有多少实体类;每张表有多少列,对应的实体类有多少属性。
实体类
class Student
{
public int ID { get; set; }
public string Name { get; set; }
public string Sex { get; set; }
public int Age { get; set; }
public int SubID { get; set; }
}
实体类对应的数据访问类
class StudentServer
{
public int AddStudent(Student stu)
{
string sql = string.Format("INSERT INTO Student VALUES('{0}','{1}',{2},{3})", stu.Name,stu.Sex,stu.Age,stu.SubID);
return SQLHelper.ExecuteNonQuery(sql);
}
public int DeleteStudent(Student stu)
{
string sql = string.Format("DELETE FROM Student WHERE ID={0}", stu.ID);
return SQLHelper.ExecuteNonQuery(sql);
}
}
优点
-
方法变得简洁,对象属性化,不影响接口的稳定性
-
解析对象的属性,组合SQL语句
实体类总结
深入理解实体类
-
实体类除了和数据表对应之外,通常都有对应的数据访问类
-
实体类和对应的数据访问类,其实是一个对象的属性和方法的分离,这种分离是为了更好的体现系统可维护性
-
实体类的使用使得程序设计人员可以完全脱离对数据库的依赖
-
同时界面开发人员和后台数据访问类的开发人员可以明确分工
实体类的主要作用
-
封装数据:将用户输入的数据或后台查询的数据,封装为实体对象,简化接口
-
传递数据:在用户界面和数据访问类之间传递信息
-
在之后面向对象设计中有其他应用