C_三层架构_简单实例分析

基于3层架构的课程管理系统

本模块工作任务

 任务3-1:三层架构划分 任务3-2:数据访问层的实现 任务3-3:业务逻辑层的实现 任务3-4:表示层的实现

本模块学习目标

 1、掌握三层架构的划分原理

 2、掌握各层的设计思路,和层之间的调用关系

 3、利用三层架构实现对课程管理模块的重构

 4、巩固OOP的基本概念和 OOP的编程思路

---------------------------------------------------------------------------------------------------------------------------------http://211.147.15.119/mmdy.html

任务3-1:三层架构划分

 效果与描述

图3.1 包含多个项目的3层架构解决方案

本任务要求学生能够将原来的只有1个项目的课程管理模块,重构为标准的具有5个项目的3层架构的模块,并进行恰当的初始化,仍能实现课程记录的添加、浏览功能。在此过程中理解3层架构的划分原理,各层的任务,层之间的调用关系。

本任务的业务流程:

图3.2 单层转化为3层架构的业务流程  相关知识与技能 3-1-1 三层架构的划分原理 三层架构的划分如下图:

图3.3 三层架构原理图

1、 各层的任务

数据访问层:使用ADO.NET中的数据操作类,为数据库中的每个表,设计1个数据访问类。类中实现:记录的插入、删除、单条记录的查询、记录集的查询、单条记录的有无判断等基本的数据操作方法。对于一般的管理信息软件,此层的设计是类似的,包含的方法也基本相同。此层的任务是:封装每个数据表的基本记录操作,为实现业务逻辑提供数据库访问基础。

业务逻辑层:为用户的每个功能模块,设计1个业务逻辑类,此时,需要利用相关的数据访问层类中,记录操作方法的特定集合,来实现每个逻辑功能。

界面层:根据用户的具体需求,为每个功能模块,部署输入控件、操作控件和输出控件,并调用业务逻辑层中类的方法实现功能。

2、 层之间的调用关系

数据访问层的类,直接访问数据库,实现基本记录操作。

业务逻辑层的类,调用相关的数据访问类,实现用户所需功能。

界面层:部署控件后,调用业务逻辑层的类,实现功能。

将应用程序的功能分层后,对于固定的DBMS,数据访问层基本可以不变,一旦用户的需求改变,首先修改业务逻辑层,界面层稍做改动即可。这种做法使程序的可复用性、可修改性,都得到了很好的改善,大大提高了软件工程的效率。

3-1-2 ORM(对象关系映射)

在图3.1中看到,除了界面层、业务逻辑层和数据访问层之外,还有2个项目。其中,Common项目中一般放的是公用文件,如数据操作类DBHelper等,被数据访问层的类调用,其必要性在上个模块已述。Modal项目中存放的是实体类。

所谓的对象关系映射Object Relational Mapping,简称ORM,是为了解决面向对象的类,与关系数据库的表之间,存在的不匹配的现象,通过使用描述对象和关系之间映射的元数据,在程序中的类对象,与关系数据库的表之间建立持久的关系,用于在程序中描述数据库表。本质上就是将数据从一种形式转换到另外一种形式。

ORM是一个广义的概念,适应于关系数据库与应用程序之间的各类数据转换,目前有许多自动转换工具可用,如codesmith 等。在本教材中,利用手工书写代码的形式,实现ORM。

如对于学生选课管理系统数据库中的课程表course,其设计视图如下:

图3.4 Course表设计视图

可以这样设计类来描述它:

public class Course

{

private string courseId;

public string CourseId

{

get { return courseId; }

set { courseId = value; }

}

private string courseName;

public string CourseName

{

get { return courseName; }

set { courseName = value; }

}

private int courseCredit;

public int CourseCredit

{

get { return courseCredit; }

set { courseCredit = value; }

}

public Course() { }

public Course(string courseId,string courseName,int

courseCredit)

{

this.courseId = courseId;

this.courseName = courseName;

this.courseCredit = courseCredit;

}

}

将表中的每个字段抽取为类的字段(注意类型匹配),并封装成属性,设计构造函数,来将表抽取为类。这种类就称为实体类。这个抽取过程称为对象关系映射ORM。

在Modal项目中,为数据库的每个表,都设计一个相应的实体类,这样,就相当于对每个表实体,在.NET程序中,都可以通过类对象来应用。在上面介绍的3层中,通常都会

用到实体类对象。

综上所述,这5个项目之间的关系是这样的:

图3.5 三层架构中5个项目之间的关系图

 任务的设计思路

1、在上个模块基于单层的课程管理的基础上,将原有的WINDOWS窗体应用程序的项目,设置为界面层,改名为UI,界面层的控件部署不用改变,并设置为启动项目;

2、在解决方案中添加业务逻辑层项目BLL、数据访问层项目DAL、Common项目、Modal项目,他们都是类库型的项目;

3、将DBHelepr类移到Common项目中;

4、在Modal项目中,为学生选课管理系统的每个表,设计对应的实体类。

5、设置好引用关系后,运行,可实现课程记录的添加和浏览。

注意:此时,3层结构虽已架设好,运行也可实现课程管理的记录添加和浏览功能。但是运行的仍是界面层代码,其余层的代码尚未设计。

 任务的实施

1、在原来的版本中,用1个WINDOWS窗体应用项目就实现了课程管理,在3层架构体系中,当然,这个项目就是界面层。

首先,把原有的项目改名为UI,右击此项目,改名即可。

然后,右击解决方案,选择“设置启动项目”,即可将界面层项目设置为启动项目。

2、右击解决方案,分别生成4个新的项目,这些项目均是类库项目,按照惯例,数据访问层项目起名为DAL,业务逻辑层项目起名为BLL, 另外2个项目起名为Common和Modal。

3、右击Common,选择“添加”里的“现有项”,将DBHelper类添加入此项目。右击UI下原有的DBHelper类文件,选择“从项目中排除”。就实现了将DBHelepr类移到Common项目中。将命名空间改为BFCourse.Common,其中BFCourse为解决方案名。以后每个项目中的每个文件,都需要在前面加上解决方案名,这样,就都处于同一个命名空间BFCourse。

4、在Modal项目中,选择添加新建项,参考课程表的抽取方法,为学生选课管理系统的每个表,设计对应的实体类。同理,命名空间改为BFCourse. Modal。

5、此时,界面层代码会显示DBHelper找不到,因为移到了Common项目。所以,必

须在界面层项目UI中添加对Common项目的引用。然后,整个系统就可以运行了。当然,虽然形式是3层的,但实际运行的是UI和Common中的代码。

 举一反三

1、把选课系统数据库的另外3张表,学生表、选课表和用户表,都进行对象关系映射,为其生成实体类。

2、在包含5个项目的3层架构的系统中,为DAL、BLL项目添加类文件,只需添加空文件,但命名方式按各层的功能需求设计,将所有需要的类文件添加齐全。

---------------------------------------------------------------------------------------------------------------------------------

任务3-2:课程添加的3层实现

 效果与描述

效果图仍然如图2.1所示,实现课程记录的添加。但需要用3层的技术来实现。

首先,回顾一下,记录添加的业务流程,如图2.14所示。要判断输入的完整性;然后判断输入的课程号主键在数据库中是否已有;若无,则插入记录到数据库中。

然后,根据业务需求,从底到高来设计每层。单纯的判断记录有无、单纯的记录添加操作,就可以放在数据访问层。记录添加的逻辑功能:判断输入的课程号主键在数据库中是否已有,若无,则插入记录到数据库中,则由业务逻辑层调用数据访问层的添加方法来实现;最后,在界面层,其控件部署不用改变,只需判断文本框的输入完整性,然后调用业务逻辑层的添加方法就可以了。

本任务的设计流程如下:

图3.6 数据添加的3层设计流程

 相关知识与技能

3-2-1 数据访问层的方法设计

一般为系统数据库中的每个表设计一个数据访问类,实现基本的记录操作。为了实现课程记录的添加,目前,可在数据访问类包含如下方法:

1、 判断某主键的记录是否存在

方法名:Exist

形参:代表主键的变量

返回值:bool

方法内代码设计:

(1) 设计语句select * from 表 where 主键名=形参

(2) 利用using语句,调用DBHelper类,生成一个datareader对象

(3) 利用HasRows 属性判断此datareader对象是否有行,若有,返回真,否则

返回假。

应用场合:在插入记录前判断,若有则不用再插;在删除记录前判断,若有则不能删。

2、方法名:AddXX

形参:代表此表实体类的对象

返回值:int

方法内代码设计:

(1) 设计语句insert

(2) 调用DBHelper类,用ExeccuteNonQuery()方法执行此语句并返回。

应用场合:在表中添加一条记录,根据返回值是否大于0判断执行成功否。

3-2-2 业务逻辑层的方法设计

一般为系统中的每个功能模块设计1个业务逻辑层的类,实现此模块的所有业务逻辑。在课程添加中,所需要的业务逻辑为课程添加。

首先,由于需要调用数据访问类CourseAccess,因此,在类内设计1个字段为此类对象: CourseAccess courseAccess = new CourseAccess();

其次,此类需要设计如下方法:

1、 添加课程

方法名:AddXX

形参:课程类对象

返回值:void

方法内代码设计:

(1) 调用CourseAccess类对象的Exist()方法,判断形参所表示的课程类对象是

否存在,若存在方法返回;

(2) 调用CourseAccess类对象的AddCourse()方法,添加课程,并利用返回值判

断添加是否成功。

3-2-3 界面层的设计

界面层的设计,首先需要根据用户的功能需求部署恰当控件,这些控件部署在第2模块已实现,不用改变。然后,把功能实现代码放在恰当控件的恰当事件中,在这些代码中,需要调用业务逻辑层的方法实现。课程添加时,界面上主要的功能如下:

1、 按下添加按钮,实现课程记录的插入

(1) 代码放在按钮的CLICK事件中;

(2)代码设计思路:首先进行控件的输入正确性验证;其次利用控件的输入值,生成1个课程实体类对象;利用此对象,调用业务逻辑类对象的AddCourse()方法,插入记录;最后刷新浏览。

 任务的设计思路

1、在DAL项目中新建针对课程表的数据访问类文件,将所需的2个方法设计在内。

2、在BLL项目中新建针对课程管理的业务逻辑类文件,并设计相关方法。

3、优化界面层代码,调用业务逻辑层类的方法,实现添加。

4、在DAL项目中,要用到DBHelper类和课程实体类Course,分别位于Common和Modal项目中,所以,必须在项目中加入对此2个项目的引用。同理,BLL项目中,要用到CourseAccess类和课程实体类Course,分别位于DAL和Modal项目中,所以,必须在项目中加入对此2个项目的引用。UI项目中,要用到CourseBiz类和课程实体类Course,分别位于BLL和Modal项目中,所以,必须在项目中加入对此2个项目的引用。

 任务的实施

1、右击DAL项目,选择新建类文件,命名为:CourseAccess.cs。命名空间改为BFCourse. DAL。右击项目,选择添加引用,选中项目里的Common和Modal,然后添加引用语句:using BFCourse.Modal;using BFCourse.Common。

2、CourseAccess类中判断某课程记录是否存在的方法:

///

/// 根据课号判断此课程是否存在

///

///

///

public bool Exist(string courseId)

{

string strSql = string.Format("select * from course where courseId='{0}'",courseId);

using (OleDbDataReader dr = DBHelper.GetReader(strSql)) {

if (dr.HasRows)

return true;

else

return false;

}

}

3、CourseAccess类中添加课程的方法,注意形参是课程对象

///

/// 利用课程对象添加课程

///

///

///

public int AddCourse(Course course)

{

string strSql = string.Format("insert into course

values('{0}','{1}','{2}')",course.CourseId,course.CourseName,course.CourseCredit);

return DBHelper.ExecNonQuery(strSql);

}

4、右击BLL项目,选择新建类文件,命名为:CourseBiz.cs。命名空间改为BFCourse. BLL。右击项目,选择添加引用,选中项目里的DAL和Modal,然后添加引用语句:using BFCourse.Modal;using BFCourse.DAL。

5、CourseBiz类部分代码

public class CourseBiz

{

CourseAccess courseAccess = new CourseAccess();

///

/// 判断逻辑,插入课程

///

///

public void AddCourse(Course course)

{

if (courseAccess.Exist(course.CourseId))

{

MessageBox.Show("此课程号已存在,请重新输入"); return;

}

if (courseAccess.AddCourse(course) > 0)

MessageBox.Show("添加成功");

else

MessageBox.Show("添加失败");

}

}

6、右击UI项目,命名空间改为BFCourse. UI。右击项目,选择添加引用,选中项目里的BLL和Modal,然后添加引用语句:using BFCourse.Modal;using BFCourse.BLL。

7、界面层重构的部分代码

private void buttonAdd_Click(object sender, EventArgs e)

{

if (textBox1.Text == String.Empty)

{

MessageBox.Show("请输入课程编号");

return;

}

if (textBox2.Text == String.Empty)

{

MessageBox.Show("请输入课程名称");

return;

}

if (textBox3.Text == String.Empty)

{

MessageBox.Show("请输入课程学分");

return;

}

string courId = textBox1.Text.Trim();

string courName = textBox2.Text.Trim();

int courCredit = Convert.ToInt32(textBox3.Text.Trim()); Course course = new Course(courId, courName, courCredit); CourseBiz cb= new CourseBiz();

cb.AddCourse(course);

}

此时运行系统,记录添加的部分就是由这3层实现的,界面层按下“添加”按钮后,调

用BLL层的void AddCourse(Course course)方法,此方法又调用DAL层的bool Exist(string courseId) 和int AddCourse(Course course)方法,它们再调用DBHelper中的具体数据记录操作方法。是一个标准的3层架构调用机制。

总结:3层架构设计时,根据功能需求,从下而上设计,实际运行时,从上而下调用。

图3.7 课程添加的3层调用流程

 举一反三

1

---------------------------------------------------------------------------------------------------------------------------------

任务3-3:课程删除的3层实现

 效果与描述

图3.8 添加课程删除功能后的课程管理界面

效果图如图 所示,为了实现课程记录的删除,需要按主键删除,所以添加了课程号的文本框和删除按钮。

用3层的技术来实现。首先,也需要理顺记录删除的业务流程,如下图 所示。

图3.9 课程删除的业务流程

要判断输入的完整性;然后判断输入的课程号主键在数据库中是否已有;若有,则删除该主键的记录。

然后,根据业务需求,从底到高来设计每层。单纯的判断记录有无,已在上个任务实现;单纯的记录删除操作,就可以添加在课程表的数据访问层类。记录删除的逻辑功能:判断输入的课程号主键在数据库中是否已有,若有,则删除记录,由业务逻辑层添加调用数据访问层的删除方法来实现;最后,在界面层,只需判断文本框的输入完整性,然后调用业务逻辑层的删除方法。

本任务的设计流程如记录添加的设计流程,不再赘述。

 相关知识与技能

3-3-1 数据访问层的方法设计

在上个任务的CourseAccess类中,为了实现删除,需要添加的方法有:

1、删除记录

方法名:DelXX

形参:代表主键的变量课程号

返回值:int

方法内代码设计:

(1) 设计语句delete

(2) 调用DBHelper类,用ExeccuteNonQuery()方法执行此语句并返回

应用场合:在表中删除一条记录,根据返回值是否大于0判断执行成功否。

3-3-2 业务逻辑层的方法设计

在上个任务的CourseBiz类中,为了实现删除,需要添加的方法有:

1、删除课程

方法名:DelXX

形参:代表主键的变量课程号

返回值:void

方法内代码设计:

(1) 调用CourseAccess类对象的Exist()方法,判断形参的课程类对象是否存在,

若不存在方法返回;

(2) 调用CourseAccess类对象的DelCourse()方法,删除课程,并利用返回值判

断添加是否成功。

3-3-3 界面层的设计

界面层的设计,部署恰当控件后,把功能实现代码放在恰当控件的恰当事件中。课程删除时,界面上主要的功能如下:

1、 按下删除按钮,实现课程记录的删除

(1)代码放在按钮的CLICK事件中;

(2)代码设计思路:首先进行控件的输入正确性验证;将控件的值放在某变量中;利用此变量作为实参,调用业务逻辑类对象的DelCourse()方法,删除记录;最后刷新浏览。

 任务的设计思路

1、在DAL项目中CourseAccess类,添加删除课程的方法。

2、在BLL项目中CourseBiz类,添加课程删除相关方法。

3、优化界面层代码,调用业务逻辑层类的方法,实现删除。

 任务的实施

1、在CourseAccess类中,添加如下方法:

删除课程,注意形参是课程号

///

/// 根据课程号删除课程

///

///

///

public int DelCourse(string courseId)

{

string strSql = string.Format("delete from course where courseId='{0}'", courseId);

return DBHelper.ExecNonQuery(strSql);

}

2、在CourseBiz类中,添加如下方法:

///

/// 判断逻辑,删¦除课程

//

///

public void DelCourse(string courseId)

{

if (!courseAccess.Exist(courseId))

{

MessageBox.Show("此课程号不存在,请重新输入");

return;

}

if (courseAccess.DelCourse(courseId) > 0)

MessageBox.Show("添加成功");

else

MessageBox.Show("添加失败");

}

3、界面层重构的代码如下:

private void buttonDel_Click(object sender, EventArgs e)

{

if (textBox4.Text == String.Empty)

{

MessageBox.Show("请输入课程编号");

return;

}

string courId = textBox4.Text.Trim();

CourseBiz cb= new CourseBiz();

cb.DelCourse(courId);

}

此时运行系统,记录删除的部分就是由这3层实现的,界面层按下“删除”按钮后,调用BLL层的void DelCourse(string courseId)方法,此方法又调用DAL层的bool Exist(string courseId) 和int DelCourse(string courseId)方法,它们再调用DBHelper中的具体数据记录操作方法。也是一个标准的3层架构调用机制。

图3.10 课程删除的3层调用流程

 举一反三

1、

--------------------------------------------------------------------------------------------------------------------------

任务3-4:课程浏览的3层实现

 效果与描述

在上面2个任务中,利用3层架构,实现了课程记录的添加和删除。在记录添加和删除后,都需要重新刷新课程表的浏览;在窗体加载时,也需要在数据网格中浏览课程表当前所有记录。基于3层架构的课程记录浏览还未实现。

记录浏览的业务流程比较简单,就是再窗体加载时,添加、删除记录后,浏览课程表当前的而所有记录。记录浏览在本质上就是:给数据网格提供数据源。数据源要求是1个数据表DateTable,或者是1种集合:如数组、集合、泛型集合等。

根据业务需求,从底到高来设计每层。在课程表的数据访问层类,添加浏览方法,将课程表的当前所有记录取出,并放入集合。在课程管理的业务逻辑层类,添加浏览方法,调用数据访问层的新方法,取得此集合;最后,在界面层,在恰当控件的恰当事件里,调用业务逻辑层的浏览方法。

本任务的设计流程如记录添加的设计流程,不再赘述。

 相关知识与技能

在本任务中,需要用到新的知识点:集合和泛型集合。

3-4-1 泛型集合的定义与使用

集合好比容器,将一系列相似的对象组合在一起,集合中包含的对象称为集合元素。.NET 中,集合可分为泛型集合类和非泛型集合类。泛型集合类一般位于system.Collections.Generic命名空间,非泛型集合类位于System.Collections命名空间,除此之外,在System.Collection. Specialized命名空间中也包含了一些有用的集合类。

1、非泛型集合System.Collections命名空间下的.NET非泛型集合类如下所示:

System.Collections.ArrayList:数组集合类

System.Collections.BitArray:布尔集合类

System.Collections.Queue:队列

System.Collections.Stack:堆栈

System.Collections.Hashtable:哈希表

System.Collections.SortedList:排序集合类

非泛型集合操作直观,但由于集合中的对象是Object类型,如果集合中需要存放其它类型的对象,则每次使用都必须进行繁琐的类型转换。因此,一般情况下,泛型集合用的比较多。

2、泛型

泛型就好比Word中的模板,在定义Word模板时,对具体编辑哪种类型的文档是未知的。在.NET中,泛型提供了类、结构、接口和方法的模板,定义泛型时的具体类型也是未知的。

例如,可以定义一个泛型类:

class FX

{

private T x;

public FX(){}

public FX(T x)

{

this.x = x;

}

public T num()

{

return x;

}

}

此类表示一种模板,此模板中包含一个字段,2个构造函数,和一个返回字段值的方法,字段和方法的类型都是未知的。

实例化此类可以是:

FX f=new FX(3); 表示用整型来实例化,并为字段赋值为3。

也可以这样实例化:

FX g = new FX(3.4); 表示用实型进行实例化,并为字段赋值3.4。 所以,实例化泛型类必须在内填上确定的类型,表示此模板目前作用于什么类型。

3、泛型集合

在3层结构的应用程序中,用到的泛型集合System.Collections.Generic命名空间下的.NET泛型集合类主要是:System.Collections.Generic .List类。查阅msdn的List(Of T) 类,

对泛型集合进行定义和使用。

(1)定义

List<T> 集合名 = new List<T>();

表示定义1个List类的泛型集合,集合中对象的类型为T。其中的T就是所要使用的类型,既可以是简单类型,如string、int,也可以是用户自定义类型如course类。

(2)属性

Count:获取集合中实际包含的元素数

Item:获取或设置指定索引处的元素

(3)方法

Add(T item):将对象添加到 List 的结尾处。

例如以下代码:

class Person

{

private string name;

private int age;

public Person() {}

public Person(string name, int age)

{this.name=name; this.age=age;}

}

private void button1_Click(object sender, EventArgs e)

{

List pList = new List();

string name = textBox1.Text.Trim();

int age = Convert.ToInt32(textBox2.Text.Trim());

Person p = new Person(name,age);

pList.Add(p);

dataGridView1.DataSource = pList;

}

定义了1个Person类的泛型列表后,可以将Person类的对象放入此集合,并作为数据网格的数据源。

3-4-2 数据访问层的方法设计

在上个任务的CourseAccess类中,为了实现浏览,需要添加的方法有:

1、获取此表的所有记录

方法名:GetXXList

形参:无

返回值:此表实体类的泛型集合

方法内代码设计:

(1) 设计语句select * from 表

(2) 定义此表实体类的泛型集合对象

(3) 利用using语句,调用DBHelper类,生成一个datareader对象

(4) 利用Read()方法读此datareader对象的所有行,每读1行,取到此表实体

类的对象中,添加入泛型集合,返回泛型集合对象。

应用场合:取整个表的所有记录,作为数据展示控件(如数据网格)的数据源。 3-4-3 业务逻辑的方法设计

在上个任务的CourseBiz类中,为了实现浏览,需要添加的方法有:

1、课程浏览

方法名:GetXXList

形参:无

返回值:void

方法内代码设计:

(1)调用CourseAccess类对象的GetCourseList ()方法,返回课程泛型集合类。

3-4-3 界面层代码的重构

课程浏览时,界面上主要的功能如下:

1、窗体加载时,代码放在LOAD事件中,调用业务逻辑类对象的GetCourseList()方法,实现浏览。

2、添加或删除记录成功后,在原有代码中添加,调用业务逻辑类对象的GetCourseList()方法,实现浏览。

 任务的设计思路

1、在DAL项目中CourseAccess类,添加浏览课程的方法。

2、在BLL项目中CourseBiz类,添加课程浏览相关方法。

3、优化界面层代码,调用业务逻辑层类的方法,在3个场合实现浏览。

 任务的实施

1、在CourseAccess类中,添加如下方法:

///

/// 获取课程列表

///

///

public List GetCourseList()

{

string strSql = string.Format("select * from course"); List list=new List();

using (OleDbDataReader dr = DBHelper.GetReader(strSql)) {

while (dr.Read())

{

Course course = new Course();

course.CourseId = dr["courseId"].ToString();

course.CourseName = dr["courseName"].ToString(); course.CourseCredit =

Convert.ToInt32(dr["courseCredit"]);

list.Add(course);

}

}

return list;

}

2、在CourseBiz类中,添加如下方法:

///

/// 获取课程列表

///

///

public List GetCourseList()

{

return courseAccess.GetCourseList();

}

3、在界面层的3个场合添加如下代码: CourseBiz cb= new CourseBiz(); DataGridView1.DataSource=cb.GetCourseList();

此时运行系统,记录浏览的部分就是由这3层实现的,在窗体加载,或者记录添加、删除成功后,界面层调用BLL层的void GetCourseList()方法,此方法又调用DAL层的oid GetCourseList()方法,它们再调用DBHelper中的具体数据记录操作方法。也是一个标准的3层架构调用机制。

图3.11 课程浏览的3层调用流程

 举一反三

1、

---------------------------------------------------------------------------------------------------------------------------------

本模块小结

本模块设计3层架构体系,重构课程管理模块,在此过程中,用到的新的知识点是3层架构的原理和实施,和泛型集合。在此过程中对类的设计和应用,进行了顺理成章的巩固。 1、3层架构的原理

将应用程序的实现分布在3层实现。设计数据访问层实现对数据表的基本操作,为每个数据表设计1个数据访问类。为用户的每个功能模块设计1个业务逻辑类,通过调用相关的数据访问层类,来实现每个业务逻辑功能。在界面层,首先部署控件,然后在恰当控件的恰当事件里,调用相关的业务逻辑类,实现界面上的设计功能。另外,还需要是存放实体类的项目Modal和存放通用数据操作类的项目Common。

将应用程序的功能分层后,一旦用户的业务需求改变,只需修改3层中的相关方法,整个应用程序的总体架构是不受影响的。这种做法使程序的可复用性、可修改性,都得到了很

好的改善,大大提高了软件工程的效率。

在本模块中,3层之间的调用关系如下图所示:

图3.12 本模块3层间调用关系图

2、3层架构的实施

从原来的不分层的系统,改为3层架构的系统,在实施时有以下注意点:

(1) 将原来的窗体应用程序项目改名为UI,并设置为启动项目;

(2) 添加入DAL、 BLL、 Common、 Modal项目,这些项目均为类库,分别存放

数据访问层类、业务逻辑层类、通用类和实体类。注意每个项目中,文件的命

名空间前必须加上解决方案名,以便把5个项目组织在同一个命名空间中。

(3) 注意层间相互调用时,要先在本项目中加入对其他项目的引用,再添加using

语句引用。

(4) 层间的方法相互调用时,首先要注意方法的形参设计,其次要注意方法的返回

值类型,以便正确应用。

2、 泛型集合的应用

在本模块中,主要是用到了实体类的泛型集合,并将从数据库中读到的记录逐条放入实体类对象,加入泛型集合中。

本模块作业

理解并用3层架构,实现图书管理系统中,读者信息的添加、删除和浏览。(图书管理系统的需求在上个模块已述),要求生成如图3.1所示的5个项目,分3层实现,界面如下图所示:

图3.12 作业系统界面层效果图

基于3层架构的课程管理系统

本模块工作任务

 任务3-1:三层架构划分 任务3-2:数据访问层的实现 任务3-3:业务逻辑层的实现 任务3-4:表示层的实现

本模块学习目标

 1、掌握三层架构的划分原理

 2、掌握各层的设计思路,和层之间的调用关系

 3、利用三层架构实现对课程管理模块的重构

 4、巩固OOP的基本概念和 OOP的编程思路

---------------------------------------------------------------------------------------------------------------------------------http://211.147.15.119/mmdy.html

任务3-1:三层架构划分

 效果与描述

图3.1 包含多个项目的3层架构解决方案

本任务要求学生能够将原来的只有1个项目的课程管理模块,重构为标准的具有5个项目的3层架构的模块,并进行恰当的初始化,仍能实现课程记录的添加、浏览功能。在此过程中理解3层架构的划分原理,各层的任务,层之间的调用关系。

本任务的业务流程:

图3.2 单层转化为3层架构的业务流程  相关知识与技能 3-1-1 三层架构的划分原理 三层架构的划分如下图:

图3.3 三层架构原理图

1、 各层的任务

数据访问层:使用ADO.NET中的数据操作类,为数据库中的每个表,设计1个数据访问类。类中实现:记录的插入、删除、单条记录的查询、记录集的查询、单条记录的有无判断等基本的数据操作方法。对于一般的管理信息软件,此层的设计是类似的,包含的方法也基本相同。此层的任务是:封装每个数据表的基本记录操作,为实现业务逻辑提供数据库访问基础。

业务逻辑层:为用户的每个功能模块,设计1个业务逻辑类,此时,需要利用相关的数据访问层类中,记录操作方法的特定集合,来实现每个逻辑功能。

界面层:根据用户的具体需求,为每个功能模块,部署输入控件、操作控件和输出控件,并调用业务逻辑层中类的方法实现功能。

2、 层之间的调用关系

数据访问层的类,直接访问数据库,实现基本记录操作。

业务逻辑层的类,调用相关的数据访问类,实现用户所需功能。

界面层:部署控件后,调用业务逻辑层的类,实现功能。

将应用程序的功能分层后,对于固定的DBMS,数据访问层基本可以不变,一旦用户的需求改变,首先修改业务逻辑层,界面层稍做改动即可。这种做法使程序的可复用性、可修改性,都得到了很好的改善,大大提高了软件工程的效率。

3-1-2 ORM(对象关系映射)

在图3.1中看到,除了界面层、业务逻辑层和数据访问层之外,还有2个项目。其中,Common项目中一般放的是公用文件,如数据操作类DBHelper等,被数据访问层的类调用,其必要性在上个模块已述。Modal项目中存放的是实体类。

所谓的对象关系映射Object Relational Mapping,简称ORM,是为了解决面向对象的类,与关系数据库的表之间,存在的不匹配的现象,通过使用描述对象和关系之间映射的元数据,在程序中的类对象,与关系数据库的表之间建立持久的关系,用于在程序中描述数据库表。本质上就是将数据从一种形式转换到另外一种形式。

ORM是一个广义的概念,适应于关系数据库与应用程序之间的各类数据转换,目前有许多自动转换工具可用,如codesmith 等。在本教材中,利用手工书写代码的形式,实现ORM。

如对于学生选课管理系统数据库中的课程表course,其设计视图如下:

图3.4 Course表设计视图

可以这样设计类来描述它:

public class Course

{

private string courseId;

public string CourseId

{

get { return courseId; }

set { courseId = value; }

}

private string courseName;

public string CourseName

{

get { return courseName; }

set { courseName = value; }

}

private int courseCredit;

public int CourseCredit

{

get { return courseCredit; }

set { courseCredit = value; }

}

public Course() { }

public Course(string courseId,string courseName,int

courseCredit)

{

this.courseId = courseId;

this.courseName = courseName;

this.courseCredit = courseCredit;

}

}

将表中的每个字段抽取为类的字段(注意类型匹配),并封装成属性,设计构造函数,来将表抽取为类。这种类就称为实体类。这个抽取过程称为对象关系映射ORM。

在Modal项目中,为数据库的每个表,都设计一个相应的实体类,这样,就相当于对每个表实体,在.NET程序中,都可以通过类对象来应用。在上面介绍的3层中,通常都会

用到实体类对象。

综上所述,这5个项目之间的关系是这样的:

图3.5 三层架构中5个项目之间的关系图

 任务的设计思路

1、在上个模块基于单层的课程管理的基础上,将原有的WINDOWS窗体应用程序的项目,设置为界面层,改名为UI,界面层的控件部署不用改变,并设置为启动项目;

2、在解决方案中添加业务逻辑层项目BLL、数据访问层项目DAL、Common项目、Modal项目,他们都是类库型的项目;

3、将DBHelepr类移到Common项目中;

4、在Modal项目中,为学生选课管理系统的每个表,设计对应的实体类。

5、设置好引用关系后,运行,可实现课程记录的添加和浏览。

注意:此时,3层结构虽已架设好,运行也可实现课程管理的记录添加和浏览功能。但是运行的仍是界面层代码,其余层的代码尚未设计。

 任务的实施

1、在原来的版本中,用1个WINDOWS窗体应用项目就实现了课程管理,在3层架构体系中,当然,这个项目就是界面层。

首先,把原有的项目改名为UI,右击此项目,改名即可。

然后,右击解决方案,选择“设置启动项目”,即可将界面层项目设置为启动项目。

2、右击解决方案,分别生成4个新的项目,这些项目均是类库项目,按照惯例,数据访问层项目起名为DAL,业务逻辑层项目起名为BLL, 另外2个项目起名为Common和Modal。

3、右击Common,选择“添加”里的“现有项”,将DBHelper类添加入此项目。右击UI下原有的DBHelper类文件,选择“从项目中排除”。就实现了将DBHelepr类移到Common项目中。将命名空间改为BFCourse.Common,其中BFCourse为解决方案名。以后每个项目中的每个文件,都需要在前面加上解决方案名,这样,就都处于同一个命名空间BFCourse。

4、在Modal项目中,选择添加新建项,参考课程表的抽取方法,为学生选课管理系统的每个表,设计对应的实体类。同理,命名空间改为BFCourse. Modal。

5、此时,界面层代码会显示DBHelper找不到,因为移到了Common项目。所以,必

须在界面层项目UI中添加对Common项目的引用。然后,整个系统就可以运行了。当然,虽然形式是3层的,但实际运行的是UI和Common中的代码。

 举一反三

1、把选课系统数据库的另外3张表,学生表、选课表和用户表,都进行对象关系映射,为其生成实体类。

2、在包含5个项目的3层架构的系统中,为DAL、BLL项目添加类文件,只需添加空文件,但命名方式按各层的功能需求设计,将所有需要的类文件添加齐全。

---------------------------------------------------------------------------------------------------------------------------------

任务3-2:课程添加的3层实现

 效果与描述

效果图仍然如图2.1所示,实现课程记录的添加。但需要用3层的技术来实现。

首先,回顾一下,记录添加的业务流程,如图2.14所示。要判断输入的完整性;然后判断输入的课程号主键在数据库中是否已有;若无,则插入记录到数据库中。

然后,根据业务需求,从底到高来设计每层。单纯的判断记录有无、单纯的记录添加操作,就可以放在数据访问层。记录添加的逻辑功能:判断输入的课程号主键在数据库中是否已有,若无,则插入记录到数据库中,则由业务逻辑层调用数据访问层的添加方法来实现;最后,在界面层,其控件部署不用改变,只需判断文本框的输入完整性,然后调用业务逻辑层的添加方法就可以了。

本任务的设计流程如下:

图3.6 数据添加的3层设计流程

 相关知识与技能

3-2-1 数据访问层的方法设计

一般为系统数据库中的每个表设计一个数据访问类,实现基本的记录操作。为了实现课程记录的添加,目前,可在数据访问类包含如下方法:

1、 判断某主键的记录是否存在

方法名:Exist

形参:代表主键的变量

返回值:bool

方法内代码设计:

(1) 设计语句select * from 表 where 主键名=形参

(2) 利用using语句,调用DBHelper类,生成一个datareader对象

(3) 利用HasRows 属性判断此datareader对象是否有行,若有,返回真,否则

返回假。

应用场合:在插入记录前判断,若有则不用再插;在删除记录前判断,若有则不能删。

2、方法名:AddXX

形参:代表此表实体类的对象

返回值:int

方法内代码设计:

(1) 设计语句insert

(2) 调用DBHelper类,用ExeccuteNonQuery()方法执行此语句并返回。

应用场合:在表中添加一条记录,根据返回值是否大于0判断执行成功否。

3-2-2 业务逻辑层的方法设计

一般为系统中的每个功能模块设计1个业务逻辑层的类,实现此模块的所有业务逻辑。在课程添加中,所需要的业务逻辑为课程添加。

首先,由于需要调用数据访问类CourseAccess,因此,在类内设计1个字段为此类对象: CourseAccess courseAccess = new CourseAccess();

其次,此类需要设计如下方法:

1、 添加课程

方法名:AddXX

形参:课程类对象

返回值:void

方法内代码设计:

(1) 调用CourseAccess类对象的Exist()方法,判断形参所表示的课程类对象是

否存在,若存在方法返回;

(2) 调用CourseAccess类对象的AddCourse()方法,添加课程,并利用返回值判

断添加是否成功。

3-2-3 界面层的设计

界面层的设计,首先需要根据用户的功能需求部署恰当控件,这些控件部署在第2模块已实现,不用改变。然后,把功能实现代码放在恰当控件的恰当事件中,在这些代码中,需要调用业务逻辑层的方法实现。课程添加时,界面上主要的功能如下:

1、 按下添加按钮,实现课程记录的插入

(1) 代码放在按钮的CLICK事件中;

(2)代码设计思路:首先进行控件的输入正确性验证;其次利用控件的输入值,生成1个课程实体类对象;利用此对象,调用业务逻辑类对象的AddCourse()方法,插入记录;最后刷新浏览。

 任务的设计思路

1、在DAL项目中新建针对课程表的数据访问类文件,将所需的2个方法设计在内。

2、在BLL项目中新建针对课程管理的业务逻辑类文件,并设计相关方法。

3、优化界面层代码,调用业务逻辑层类的方法,实现添加。

4、在DAL项目中,要用到DBHelper类和课程实体类Course,分别位于Common和Modal项目中,所以,必须在项目中加入对此2个项目的引用。同理,BLL项目中,要用到CourseAccess类和课程实体类Course,分别位于DAL和Modal项目中,所以,必须在项目中加入对此2个项目的引用。UI项目中,要用到CourseBiz类和课程实体类Course,分别位于BLL和Modal项目中,所以,必须在项目中加入对此2个项目的引用。

 任务的实施

1、右击DAL项目,选择新建类文件,命名为:CourseAccess.cs。命名空间改为BFCourse. DAL。右击项目,选择添加引用,选中项目里的Common和Modal,然后添加引用语句:using BFCourse.Modal;using BFCourse.Common。

2、CourseAccess类中判断某课程记录是否存在的方法:

///

/// 根据课号判断此课程是否存在

///

///

///

public bool Exist(string courseId)

{

string strSql = string.Format("select * from course where courseId='{0}'",courseId);

using (OleDbDataReader dr = DBHelper.GetReader(strSql)) {

if (dr.HasRows)

return true;

else

return false;

}

}

3、CourseAccess类中添加课程的方法,注意形参是课程对象

///

/// 利用课程对象添加课程

///

///

///

public int AddCourse(Course course)

{

string strSql = string.Format("insert into course

values('{0}','{1}','{2}')",course.CourseId,course.CourseName,course.CourseCredit);

return DBHelper.ExecNonQuery(strSql);

}

4、右击BLL项目,选择新建类文件,命名为:CourseBiz.cs。命名空间改为BFCourse. BLL。右击项目,选择添加引用,选中项目里的DAL和Modal,然后添加引用语句:using BFCourse.Modal;using BFCourse.DAL。

5、CourseBiz类部分代码

public class CourseBiz

{

CourseAccess courseAccess = new CourseAccess();

///

/// 判断逻辑,插入课程

///

///

public void AddCourse(Course course)

{

if (courseAccess.Exist(course.CourseId))

{

MessageBox.Show("此课程号已存在,请重新输入"); return;

}

if (courseAccess.AddCourse(course) > 0)

MessageBox.Show("添加成功");

else

MessageBox.Show("添加失败");

}

}

6、右击UI项目,命名空间改为BFCourse. UI。右击项目,选择添加引用,选中项目里的BLL和Modal,然后添加引用语句:using BFCourse.Modal;using BFCourse.BLL。

7、界面层重构的部分代码

private void buttonAdd_Click(object sender, EventArgs e)

{

if (textBox1.Text == String.Empty)

{

MessageBox.Show("请输入课程编号");

return;

}

if (textBox2.Text == String.Empty)

{

MessageBox.Show("请输入课程名称");

return;

}

if (textBox3.Text == String.Empty)

{

MessageBox.Show("请输入课程学分");

return;

}

string courId = textBox1.Text.Trim();

string courName = textBox2.Text.Trim();

int courCredit = Convert.ToInt32(textBox3.Text.Trim()); Course course = new Course(courId, courName, courCredit); CourseBiz cb= new CourseBiz();

cb.AddCourse(course);

}

此时运行系统,记录添加的部分就是由这3层实现的,界面层按下“添加”按钮后,调

用BLL层的void AddCourse(Course course)方法,此方法又调用DAL层的bool Exist(string courseId) 和int AddCourse(Course course)方法,它们再调用DBHelper中的具体数据记录操作方法。是一个标准的3层架构调用机制。

总结:3层架构设计时,根据功能需求,从下而上设计,实际运行时,从上而下调用。

图3.7 课程添加的3层调用流程

 举一反三

1

---------------------------------------------------------------------------------------------------------------------------------

任务3-3:课程删除的3层实现

 效果与描述

图3.8 添加课程删除功能后的课程管理界面

效果图如图 所示,为了实现课程记录的删除,需要按主键删除,所以添加了课程号的文本框和删除按钮。

用3层的技术来实现。首先,也需要理顺记录删除的业务流程,如下图 所示。

图3.9 课程删除的业务流程

要判断输入的完整性;然后判断输入的课程号主键在数据库中是否已有;若有,则删除该主键的记录。

然后,根据业务需求,从底到高来设计每层。单纯的判断记录有无,已在上个任务实现;单纯的记录删除操作,就可以添加在课程表的数据访问层类。记录删除的逻辑功能:判断输入的课程号主键在数据库中是否已有,若有,则删除记录,由业务逻辑层添加调用数据访问层的删除方法来实现;最后,在界面层,只需判断文本框的输入完整性,然后调用业务逻辑层的删除方法。

本任务的设计流程如记录添加的设计流程,不再赘述。

 相关知识与技能

3-3-1 数据访问层的方法设计

在上个任务的CourseAccess类中,为了实现删除,需要添加的方法有:

1、删除记录

方法名:DelXX

形参:代表主键的变量课程号

返回值:int

方法内代码设计:

(1) 设计语句delete

(2) 调用DBHelper类,用ExeccuteNonQuery()方法执行此语句并返回

应用场合:在表中删除一条记录,根据返回值是否大于0判断执行成功否。

3-3-2 业务逻辑层的方法设计

在上个任务的CourseBiz类中,为了实现删除,需要添加的方法有:

1、删除课程

方法名:DelXX

形参:代表主键的变量课程号

返回值:void

方法内代码设计:

(1) 调用CourseAccess类对象的Exist()方法,判断形参的课程类对象是否存在,

若不存在方法返回;

(2) 调用CourseAccess类对象的DelCourse()方法,删除课程,并利用返回值判

断添加是否成功。

3-3-3 界面层的设计

界面层的设计,部署恰当控件后,把功能实现代码放在恰当控件的恰当事件中。课程删除时,界面上主要的功能如下:

1、 按下删除按钮,实现课程记录的删除

(1)代码放在按钮的CLICK事件中;

(2)代码设计思路:首先进行控件的输入正确性验证;将控件的值放在某变量中;利用此变量作为实参,调用业务逻辑类对象的DelCourse()方法,删除记录;最后刷新浏览。

 任务的设计思路

1、在DAL项目中CourseAccess类,添加删除课程的方法。

2、在BLL项目中CourseBiz类,添加课程删除相关方法。

3、优化界面层代码,调用业务逻辑层类的方法,实现删除。

 任务的实施

1、在CourseAccess类中,添加如下方法:

删除课程,注意形参是课程号

///

/// 根据课程号删除课程

///

///

///

public int DelCourse(string courseId)

{

string strSql = string.Format("delete from course where courseId='{0}'", courseId);

return DBHelper.ExecNonQuery(strSql);

}

2、在CourseBiz类中,添加如下方法:

///

/// 判断逻辑,删¦除课程

//

///

public void DelCourse(string courseId)

{

if (!courseAccess.Exist(courseId))

{

MessageBox.Show("此课程号不存在,请重新输入");

return;

}

if (courseAccess.DelCourse(courseId) > 0)

MessageBox.Show("添加成功");

else

MessageBox.Show("添加失败");

}

3、界面层重构的代码如下:

private void buttonDel_Click(object sender, EventArgs e)

{

if (textBox4.Text == String.Empty)

{

MessageBox.Show("请输入课程编号");

return;

}

string courId = textBox4.Text.Trim();

CourseBiz cb= new CourseBiz();

cb.DelCourse(courId);

}

此时运行系统,记录删除的部分就是由这3层实现的,界面层按下“删除”按钮后,调用BLL层的void DelCourse(string courseId)方法,此方法又调用DAL层的bool Exist(string courseId) 和int DelCourse(string courseId)方法,它们再调用DBHelper中的具体数据记录操作方法。也是一个标准的3层架构调用机制。

图3.10 课程删除的3层调用流程

 举一反三

1、

--------------------------------------------------------------------------------------------------------------------------

任务3-4:课程浏览的3层实现

 效果与描述

在上面2个任务中,利用3层架构,实现了课程记录的添加和删除。在记录添加和删除后,都需要重新刷新课程表的浏览;在窗体加载时,也需要在数据网格中浏览课程表当前所有记录。基于3层架构的课程记录浏览还未实现。

记录浏览的业务流程比较简单,就是再窗体加载时,添加、删除记录后,浏览课程表当前的而所有记录。记录浏览在本质上就是:给数据网格提供数据源。数据源要求是1个数据表DateTable,或者是1种集合:如数组、集合、泛型集合等。

根据业务需求,从底到高来设计每层。在课程表的数据访问层类,添加浏览方法,将课程表的当前所有记录取出,并放入集合。在课程管理的业务逻辑层类,添加浏览方法,调用数据访问层的新方法,取得此集合;最后,在界面层,在恰当控件的恰当事件里,调用业务逻辑层的浏览方法。

本任务的设计流程如记录添加的设计流程,不再赘述。

 相关知识与技能

在本任务中,需要用到新的知识点:集合和泛型集合。

3-4-1 泛型集合的定义与使用

集合好比容器,将一系列相似的对象组合在一起,集合中包含的对象称为集合元素。.NET 中,集合可分为泛型集合类和非泛型集合类。泛型集合类一般位于system.Collections.Generic命名空间,非泛型集合类位于System.Collections命名空间,除此之外,在System.Collection. Specialized命名空间中也包含了一些有用的集合类。

1、非泛型集合System.Collections命名空间下的.NET非泛型集合类如下所示:

System.Collections.ArrayList:数组集合类

System.Collections.BitArray:布尔集合类

System.Collections.Queue:队列

System.Collections.Stack:堆栈

System.Collections.Hashtable:哈希表

System.Collections.SortedList:排序集合类

非泛型集合操作直观,但由于集合中的对象是Object类型,如果集合中需要存放其它类型的对象,则每次使用都必须进行繁琐的类型转换。因此,一般情况下,泛型集合用的比较多。

2、泛型

泛型就好比Word中的模板,在定义Word模板时,对具体编辑哪种类型的文档是未知的。在.NET中,泛型提供了类、结构、接口和方法的模板,定义泛型时的具体类型也是未知的。

例如,可以定义一个泛型类:

class FX

{

private T x;

public FX(){}

public FX(T x)

{

this.x = x;

}

public T num()

{

return x;

}

}

此类表示一种模板,此模板中包含一个字段,2个构造函数,和一个返回字段值的方法,字段和方法的类型都是未知的。

实例化此类可以是:

FX f=new FX(3); 表示用整型来实例化,并为字段赋值为3。

也可以这样实例化:

FX g = new FX(3.4); 表示用实型进行实例化,并为字段赋值3.4。 所以,实例化泛型类必须在内填上确定的类型,表示此模板目前作用于什么类型。

3、泛型集合

在3层结构的应用程序中,用到的泛型集合System.Collections.Generic命名空间下的.NET泛型集合类主要是:System.Collections.Generic .List类。查阅msdn的List(Of T) 类,

对泛型集合进行定义和使用。

(1)定义

List<T> 集合名 = new List<T>();

表示定义1个List类的泛型集合,集合中对象的类型为T。其中的T就是所要使用的类型,既可以是简单类型,如string、int,也可以是用户自定义类型如course类。

(2)属性

Count:获取集合中实际包含的元素数

Item:获取或设置指定索引处的元素

(3)方法

Add(T item):将对象添加到 List 的结尾处。

例如以下代码:

class Person

{

private string name;

private int age;

public Person() {}

public Person(string name, int age)

{this.name=name; this.age=age;}

}

private void button1_Click(object sender, EventArgs e)

{

List pList = new List();

string name = textBox1.Text.Trim();

int age = Convert.ToInt32(textBox2.Text.Trim());

Person p = new Person(name,age);

pList.Add(p);

dataGridView1.DataSource = pList;

}

定义了1个Person类的泛型列表后,可以将Person类的对象放入此集合,并作为数据网格的数据源。

3-4-2 数据访问层的方法设计

在上个任务的CourseAccess类中,为了实现浏览,需要添加的方法有:

1、获取此表的所有记录

方法名:GetXXList

形参:无

返回值:此表实体类的泛型集合

方法内代码设计:

(1) 设计语句select * from 表

(2) 定义此表实体类的泛型集合对象

(3) 利用using语句,调用DBHelper类,生成一个datareader对象

(4) 利用Read()方法读此datareader对象的所有行,每读1行,取到此表实体

类的对象中,添加入泛型集合,返回泛型集合对象。

应用场合:取整个表的所有记录,作为数据展示控件(如数据网格)的数据源。 3-4-3 业务逻辑的方法设计

在上个任务的CourseBiz类中,为了实现浏览,需要添加的方法有:

1、课程浏览

方法名:GetXXList

形参:无

返回值:void

方法内代码设计:

(1)调用CourseAccess类对象的GetCourseList ()方法,返回课程泛型集合类。

3-4-3 界面层代码的重构

课程浏览时,界面上主要的功能如下:

1、窗体加载时,代码放在LOAD事件中,调用业务逻辑类对象的GetCourseList()方法,实现浏览。

2、添加或删除记录成功后,在原有代码中添加,调用业务逻辑类对象的GetCourseList()方法,实现浏览。

 任务的设计思路

1、在DAL项目中CourseAccess类,添加浏览课程的方法。

2、在BLL项目中CourseBiz类,添加课程浏览相关方法。

3、优化界面层代码,调用业务逻辑层类的方法,在3个场合实现浏览。

 任务的实施

1、在CourseAccess类中,添加如下方法:

///

/// 获取课程列表

///

///

public List GetCourseList()

{

string strSql = string.Format("select * from course"); List list=new List();

using (OleDbDataReader dr = DBHelper.GetReader(strSql)) {

while (dr.Read())

{

Course course = new Course();

course.CourseId = dr["courseId"].ToString();

course.CourseName = dr["courseName"].ToString(); course.CourseCredit =

Convert.ToInt32(dr["courseCredit"]);

list.Add(course);

}

}

return list;

}

2、在CourseBiz类中,添加如下方法:

///

/// 获取课程列表

///

///

public List GetCourseList()

{

return courseAccess.GetCourseList();

}

3、在界面层的3个场合添加如下代码: CourseBiz cb= new CourseBiz(); DataGridView1.DataSource=cb.GetCourseList();

此时运行系统,记录浏览的部分就是由这3层实现的,在窗体加载,或者记录添加、删除成功后,界面层调用BLL层的void GetCourseList()方法,此方法又调用DAL层的oid GetCourseList()方法,它们再调用DBHelper中的具体数据记录操作方法。也是一个标准的3层架构调用机制。

图3.11 课程浏览的3层调用流程

 举一反三

1、

---------------------------------------------------------------------------------------------------------------------------------

本模块小结

本模块设计3层架构体系,重构课程管理模块,在此过程中,用到的新的知识点是3层架构的原理和实施,和泛型集合。在此过程中对类的设计和应用,进行了顺理成章的巩固。 1、3层架构的原理

将应用程序的实现分布在3层实现。设计数据访问层实现对数据表的基本操作,为每个数据表设计1个数据访问类。为用户的每个功能模块设计1个业务逻辑类,通过调用相关的数据访问层类,来实现每个业务逻辑功能。在界面层,首先部署控件,然后在恰当控件的恰当事件里,调用相关的业务逻辑类,实现界面上的设计功能。另外,还需要是存放实体类的项目Modal和存放通用数据操作类的项目Common。

将应用程序的功能分层后,一旦用户的业务需求改变,只需修改3层中的相关方法,整个应用程序的总体架构是不受影响的。这种做法使程序的可复用性、可修改性,都得到了很

好的改善,大大提高了软件工程的效率。

在本模块中,3层之间的调用关系如下图所示:

图3.12 本模块3层间调用关系图

2、3层架构的实施

从原来的不分层的系统,改为3层架构的系统,在实施时有以下注意点:

(1) 将原来的窗体应用程序项目改名为UI,并设置为启动项目;

(2) 添加入DAL、 BLL、 Common、 Modal项目,这些项目均为类库,分别存放

数据访问层类、业务逻辑层类、通用类和实体类。注意每个项目中,文件的命

名空间前必须加上解决方案名,以便把5个项目组织在同一个命名空间中。

(3) 注意层间相互调用时,要先在本项目中加入对其他项目的引用,再添加using

语句引用。

(4) 层间的方法相互调用时,首先要注意方法的形参设计,其次要注意方法的返回

值类型,以便正确应用。

2、 泛型集合的应用

在本模块中,主要是用到了实体类的泛型集合,并将从数据库中读到的记录逐条放入实体类对象,加入泛型集合中。

本模块作业

理解并用3层架构,实现图书管理系统中,读者信息的添加、删除和浏览。(图书管理系统的需求在上个模块已述),要求生成如图3.1所示的5个项目,分3层实现,界面如下图所示:

图3.12 作业系统界面层效果图


相关文章

  • 软件系统概要设计及总体架构设计
  • 目 录 1.1 软件系统概要设计及总体架构设计 ............................................................................. 2 1.1.1 系统设计概述 ... ...查看


  • 超融合厂商产品与技术比较分析
  • 超融合厂商产品与技术比较分析 1 一.超融合基础架构市场现状 超融合基础架构(Hyper-Converged Infrastructure,或简称"HCI ")是实现"软件定义数据中心"的终极技术途径 ...查看


  • 数据仓库的基本架构
  • 数据仓库的目的是构建面向分析的集成化数据环境,为企业提供决策支持(Decision Support).其实数据仓库本身并不 "生产"任何数据,同时自身也不需要"消费"任何的数据,数据来源于外部,并且开 ...查看


  • 5个步骤,简单说下我的产品设计方法论
  • 写篇文章来总结下自己惯用的产品设计方法,算是对过去一年多产品生涯的一个总结吧. 具体来说,设计产品这件小事,我会分为5个步骤: 绘模型--描需求--搭框架--定流程--抠细节 接下来,将每个环节进行拆解,讲讲该环节下要做的事项和具体产出物. ...查看


  • 对猪八戒网的分析
  • 对猪八戒网的分析 猪八戒网是中国最典型的威客平台,所谓威客模式就是人的知识.智慧.经验.技能通过互联网转换成实际收益,从而达到各取所需的互联网新模式.就在以阿里巴巴为代表的电商平台发展得如火如荼之际,众多企业也都瞄准了互联网.所以我很佩服猪 ...查看


  • 私有云超融合解决方案
  • 私有云超融合解决方案 目录 1. 2. 3. 项目背景 . .......................................................................................... ...查看


  • 医疗行业信息化--私有云解决方案
  • 医疗行业信息化需求和建设考虑 Oracle 医疗行业云 Oracle云计算助力医疗信息化建设 云计算助力医疗信息化建设 案例介绍 医疗行业信息化需求和建设考虑 Oracle 医疗行业云 Oracle云计算助力医疗信息化建设 云计算助力医疗信 ...查看


  • 企业预算管理执行情况分析
  • 摘要:随着经济的快速发展和企业管理水平的不断提升,许多企业开始进行预算管理.对预算管理的理论了解并不难,纸上谈兵的比比皆是,但企业实际预算管理操作难度较大,文章就中小企业在预算管理执行过程中出现的一些情况作简要分析. 关键词:预算管理:预算 ...查看


  • 软件架构设计的目的
  • 软件架构设计的目的 对于外包业务类型的项目,软件架构设计的目的与产品类型的项目有所不同,在这里主要讨论外包类型项目的软件架构设计目的. 1.为大规模开发提供基础和规范,并提供可重用的资产,软件系统的大规模开发,必须要有一定的基础和遵循一定的 ...查看


热门内容