第1章:软件系统的分层开发


本章任务

  1. 使用分层的方式实现简单查询

  2. 搭建基本的分层架构

  3. 实现基本分层系统的功能

本章目标

  1. 理解分层开发的思想

  2. 掌握搭建分层架构的方法

  3. DotNet异常处理机制及多路捕获异常

本章内容

混沌的代码

表示层+数据层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;

namespace MySchool
{
public partial class FrmSearchStudenByGrade : Form
{
#region 常量、字段的定义
public const string CAPTION = "操作提示";
DataSet ds = new DataSet(); // 数据集
SqlDataAdapter adapterStudent; // 读取学生信息的数据适配器
#endregion

public FrmSearchStudenByGrade()
{
InitializeComponent();
}

#region 事件处理
/// <summary>
/// 窗体加载时,绑定年级数据
/// </summary>
private void FrmSearchStudentNew_Load(object sender, EventArgs e)
{

//创建数据库连接
DBHelper dbhelper = new DBHelper();

try
{
// 查询年级的sql语句
StringBuilder sql = new StringBuilder("SELECT [StudentNo],[StudentName],[Gender],[BornDate] FROM [Student]");

adapterStudent = new SqlDataAdapter();
SqlCommand command = new SqlCommand(sql.ToString(), dbhelper.Connection);
adapterStudent.SelectCommand = command;

// 填充前,先清空原有的数据
if (ds.Tables["Student"] != null)
{
ds.Tables["Student"].Clear();
}

adapterStudent.Fill(ds, "Student");

//绑定数据源
this.dgvStuName.DataSource = ds.Tables["Student"];
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, CAPTION, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}

// 说明
this.lblComment.Text = string.Format("说明:{0}代表男,{1}代表女",
Convert.ToBoolean(Gender.Male),Convert.ToBoolean(Gender.Female));
}

#endregion


}
}

存在的问题

  1. 几个人共同开发:同一组件,效率低。
  2. UI层改用控制台显示:几乎重新编写
  3. 重用获取数据功能:在窗体类,不好重用

清晰的代码

从混沌到清晰:分层。

表示层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using MySchoolDAL;

namespace MySchool
{
public partial class FrmSearchStudenByGrade : Form
{
#region 变量定义

StudentService studentService = new StudentService();
DataSet dsGrade = new DataSet();
DataSet dsStudent = new DataSet();

#endregion

public FrmSearchStudenByGrade()
{
InitializeComponent();
}

#region 事件处理
/// <summary>
/// 窗体加载时,绑定年级数据
/// </summary>
private void FrmSearchStudentNew_Load(object sender, EventArgs e)
{

// 默认显示所有年级的学生
dsStudent = studentService.GetAllStudents();
this.dgvStuName.DataSource = dsStudent.Tables["Student"];

// 说明
this.lblComment.Text = string.Format("说明:{0}代表男,{1}代表女",
Convert.ToBoolean(Gender.Male),Convert.ToBoolean(Gender.Female));
}


#endregion


}
}

数据层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace MySchoolDAL
{
public class StudentService
{
public DataSet GetAllStudents()
{
DBHelper dbhelper = new DBHelper();
DataSet ds = new DataSet();
SqlDataAdapter adapterStudent;
try
{
// 查询年级的sql语句
StringBuilder sql = new StringBuilder("SELECT [StudentNo],[StudentName],[Gender],[BornDate] FROM [Student]");

adapterStudent = new SqlDataAdapter();
SqlCommand command = new SqlCommand(sql.ToString(), dbhelper.Connection);
adapterStudent.SelectCommand = command;

// 填充前,先清空原有的数据
if (ds.Tables["Student"] != null)
{
ds.Tables["Student"].Clear();
}

adapterStudent.Fill(ds, "Student");

return ds;
}
catch (Exception ex)
{
throw ex;
}
}
}
}

生活中的分层

软件开发的分层

分层架构

解决方案与项目

解决方案中可有多个项目,项目对应到层.

类库项目于程序集

  • Visual Studio 可创建自定义的类库
  • 类库项目可编译为dll(程序集)
  • 程序集是.NET应用程序的主要构造块
    • 包含编写的功能模块、功能
    • 类库程序集:dll
    • 可执行程序集:exe
  • 类库项目有默认程序集名称和命

层之间的关系

项目对应到层,层间的功能如何调用?

搭建分层架构

步骤

  1. 创建应用程序项目UI(表示层)
  2. 创建类库项目 DAL(数据访问层)
  3. 添加两层之间的依赖关系
  4. 分别实现各层的代码

常见错误

为什么需要异常处理

生活案例:网上银行:张三转账25000到李四的账户上。

异常处理机制

程序执行过程:

异常体系结构

Exception类的重要属性:

异常处理结构

定位异常类型

多路捕获异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
using System.Data.SqlClient;
namespace MyTest
{
class Program
{
static void Main(string[] args)
{
try
{
//引发异常的第1段代码
File.Delete("C:/testaccp7.0/a.test");

//引发异常的第2段代码
SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=MySchool;User ID=sa;Pwd=bdqn");
conn.Open();
conn.Close();

//引发异常的第3段代码
int i = 100;
int j = 0;
int k = i / j;


}
catch (Exception ex)
{
Console.WriteLine("出现其它异常:" + ex.ToString());
}
catch (IOException ex)
{
Console.WriteLine("出现IO 异常:" + ex.ToString());
}
catch (SqlException ex)
{
Console.WriteLine("访问数据库异常:" + ex.ToString());
}

}
}
}

抛出异常

使用throw抛出异常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Data;
using System.Data.SqlClient;
namespace MyTest
{
class Program
{
static void Test()
{
try
{
////引发异常的第1段代码
File.Delete("C:/testaccp7.0/a.test");

//引发异常的第2段代码
SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=MySchool;User ID=sa;Pwd=bdqn");
conn.Open();
conn.Close();

//引发异常的第3段代码
int i = 100;
int j = 0;
int k = i / j;
}
catch (IOException ex)
{
// throw ex;
throw;
}
catch (SqlException ex)
{
//throw ex;
throw ;
}
catch (Exception ex)
{
throw;
// throw ex;
}
}

static void Main(string[] args)
{
try
{
Test();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}

本章总结

课后作业

1.显示学生信息

2.显示年级信息

3.实现登录功能