基于.NET平台的分层架构实战(完整资料)_第1页
基于.NET平台的分层架构实战(完整资料)_第2页
基于.NET平台的分层架构实战(完整资料)_第3页
基于.NET平台的分层架构实战(完整资料)_第4页
基于.NET平台的分层架构实战(完整资料)_第5页
已阅读5页,还剩93页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

基于.NET平台的分层架构实战(完整资料)(可以直接使用,可编辑优秀版资料,欢迎下载)

通过浏览博客园的文章发现,很多朋友对分层架构特别感兴趣,刚好我刚做完的毕业设计就是专门研究.NET平台上分层架构的(题目叫“基于.NET平台的分层架构与设计模式应用研究”).通过做这篇论文,我对分层架构有了一定的了解,所以,就萌发了想写一个文章系列,详述一下分层架构。然而,论文的理论性太强,不适合在网上发布,尤其不适合初学者理解,所以,我想在这个文章系列中,少讲理论,而是通过做一个完整的案例来讨论分层架构的基本方法,这样会直观很多。希望在这个文章系列的写作过程中,能和朋友们一起学习,一起进步。

为了让朋友们把主要精力放在理解分层架构而不是案例本身,我准备选择一个相对简单的留言本系统作为Demo,这个系统的名字就叫做NGuestBook。

初步计划将这个文章系列分为以下几篇:

1.综述ﻫ

2.系统需求分析及数据库设计ﻫ

3.架构概要设计

4.实体类的实现ﻫ

5。接口的设计与实现

6。依赖注入及IoC的设计与实现

7。数据访问层的第一种实现——Access+动态生成SQL语言ﻫ

8.数据访问层的第二种实现——SQLServer+存储过程ﻫ

9.数据访问层的第三种实现——基于NBear框架的ORM实现ﻫ

10.业务逻辑层的实现

11。表示层的实现ﻫ

12。使用ASP.NETAJAX框架对表示层进行改进

13.总结

当然,以上只是初步计划,在写文章的过程中可能会根据具体情况适当调整,但是内容大体就是这些。

这个文章系列不会对所用到的技术进行详细讲解,具体请参考相关文献,阅读文章前最好能对以下技术有一个了解:ﻫ

1.C#语言ﻫ

2。ASP.NETﻫ

3.设计模式

4.关系数据库基础知识ﻫ

5.软件架构基本原则与软件工程基础知识ﻫ

6。基于NBear框架的ORM技术

7。JavaScript,Ajax

8。ASP.NETAJAX框架(特别是客户端编程)ﻫ

9.HTML,CSS,标准化布局ﻫﻫ

另外,本文章系列是基于.NETframework2.0框架平台进行讨论,3。5平台的新特性(如LINQ、ASP.NETMVC等)不会讨论,IDE使用VisualStudio2005,数据库会用到SQLServer2005Express和Access2003。基于.NET平台的分层架构实战(完整资料)(可以直接使用,可编辑优秀版资料,欢迎下载)在实际的项目中,需求分析和数据库的设计是很重要的一个环节,这个环节会直接影响项目的开发过程和质量。实际中,这个环节不但需要系统分析师、软件工程师等计算机方面的专家,还需要相关领域的领域专家参与才能完成。ﻫﻫ

但是,在这个文章系列中,所要使用的Demo仅仅是一个例子,而且其业务极为简单,因此,这里并不是真正的需求分析和数据库设计,而是将Demo的需求和数据库罗列至此,使朋友们对Demo有一个大体的了解,方便后续文章中开发过程的理解。

需求分析:

这个项目是一个留言本,其业务极为简单,现将其描述如下。

1.任何访问者可以进行留言,留言完成后,不会立即显示正文,而是要经过管理员验证后才可显示。

2。任何访问者可以对留言发表评论,未通过验证的留言不可以评论。ﻫ

3.管理员可以对留言进行回复(这个回复不同于评论,是直接显示在正文下面,而且是一个留言只能有一个回复),并可对留言与评论实行删除,以及对留言进行通过验证操作。ﻫ

4.管理员分为超级管理员和普通管理员。超级管理员只有一个,负责对普通管理员实行添加、删除操作.普通管理员可偶多个,负责对留言的管理,并可以修改自己的登录密码.

这个项目的用例图如下:ﻫ

数据库设计:ﻫ

设计数据表之前,首先进行实体和关系的识别与确定。ﻫ

通过需求分析,可以观察得出,本项目的实体有:管理员(不包括超级管理员),留言,评论。本项目的关系有:留言与评论间的一对多关系.ﻫﻫ

进一步,数据库各表的设计如下:

管理员表(TAdmin)ﻫ

ID

int

管理员ID

NotNull

主键,自增

Name

varchar(20)

登录名

NotNull

Password

varchar(50)

登录密码

NotNull

使用MD5加密ﻫﻫ

留言表(TMessage)

ID

int

留言ID

NotNull

主键,自增

GuestName

varchar(20)

留言者用户名

NotNull

GuestEmail

varchar(100)

留言者E-mail

Null

Content

text

留言内容

NotNullﻫ

Time

datetime

发表留言时间

NotNull

Reply

text

回复

Null

IsPass

varchar(10)

是否通过验证

NotNull

评论表(TComment)

Content

text

评论内容

NotNullﻫ

Time

datetime

发表评论时间

NotNull

MessageID

int

所属留言的ID

外键基于。NET平台的分层架构实战(三)—架构概要设计

本文主要是对将要实现的架构进行一个总体的描述,使朋友们对这个架构有个宏观上的认识。这篇文章理论性的东西会偏多一点,从下篇开始,将进行实际项目的开发.这篇文章的许多内容摘自我的毕业论文.架构基本原则:这里,将描述一些在这个架构设计中的基本原则,其中很多都是经典的设计原则,不过针对分层架构的特点,用我自己的语言进行了描述。其中也有我自己提出的原则。逐层调用原则及单向调用原则现在约定将N层架构的各层依次编号为1、2、…、K、…、N-1、N,其中层的编号越大,则越处在上层.那么,我们设计的架构应该满足以下两个原则:1.第K(12.如果P层依赖Q层,则P的编号一定大于Q。其中第一个原则,保证了依赖的逐层性,及整个架构的依赖是逐层向下的,而不能跨层依赖。第二个原则,则保证了依赖的单向性,及只能上层依赖底层,而不能底层反过来依赖上层。针对接口编程,而不是针对实现编程

这里所指的接口,不是特指编程语言中的具体语言元素(如C#中由Interface定义的语言接口),而是指一种抽象的,在语义层面上起着接合作用语义体。它的具体实现,可能是接口,可能是抽象类,甚至可能是具体类。我认为,从不同的视角,接口可以有以下两种定义:1.接口是一组规则的集合,它规定了实现本接口的类或接口必须拥有的一组规则。体现了自然界“如果你是……则必须能……”的理念。2。接口是在一定粒度视图上同类事物的抽象表示。注意这里我强调了在一定粒度视图上,因为“同类事物”这个概念是相对的,它因为粒度视图不同而不同。具体到N层架构中,针对接口编程的意义在部分上是这样的:ﻫ现仍约定将N层架构的各层依次编号为1、2、…、K、…、N-1、N,其中层的编号越大,则越处在上层,那么第K层不应该依赖具体一个K-1层,而应该依赖一个K-1层的接口,即在第K层中不应该有K—1层中的某个具体类.依赖倒置原则在软件设计原则中,有一种重要的思想叫做依赖倒置。它的核心思想是:不能让高层组件依赖底层组件,而且,不管高层组件和底层组件,两者都应依赖于抽象。那么,这个原则和我们上面的原则是否矛盾呢?其实并不矛盾。因为这个原则定义中的“依赖”是指“具体依赖",而上面定义中的依赖全部指“抽象依赖”。我对这两种依赖的定义如下:具体依赖——如果P层中有一个或一个以上的地方实例化了Q层中某个具体类,则说P层具体依赖于Q层。抽象依赖—-如果P层没有实例化Q层中的具体类,而是在一个或一个以上的地方实例化了Q层中某个接口,则说P层抽象依赖于Q层,也叫接口依赖于Q层。从这两个定义可以看到,所谓的依赖倒置原则,正是上面提到针对接口编程,而不是针对实现编程,两者在本质上是统一的.综上所述,可以看出,本课题设计的分层架构,应该是这样一种架构:ﻫ1。N层架构的各层依次编号为1、2、…、K、…、N—1、N,其中层的编号越大,则越处在上层。2.架构中仅存在一种依赖,即第K层接口依赖第K—1层,其中1封装变化原则封装变化的原则定义为:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混杂在一起。开放-关闭原则开发-关闭原则定义为:对扩展开放,对修改关闭.具体到N层架构中,可以描述为:当某一层有了一个新的具体实现时,它应该可以在不修改其他层的情况下,与此新实现无缝连接,顺利交互。单一归属原则在这个架构中,任何一个操作类都应该有单一的职责,属于单独的一层,而不能同时担负两种职责或属于多个层次(实体类及辅助类可以被多个层使用,但它们不属于任何一个层,而是独立存在)。层次划分:目前,典型的分层架构是三层架构,即自底向上依次是数据访问层、业务逻辑层和表示层.这种经典架构经历了时间的考验和实践的多次检验,被认为是合理、有效的分层设计,所以,在本文中,将沿袭这种经典架构,使用数据访问层、业务逻辑层和表示层的三层架构体系.职责划分:

目前,在典型的三层架构中,对层次各自的职责划分并没有一个统一的规范,综合现有的成功实践和.NET平台的特殊性,在本文中将三层架构的职责划分如下:

数据访问层--负责与数据源的交互,即数据的插入、删除、修改以及从数据库中读出数据等操作。对数据的正确性和有效性不负责,对数据的用途不了解,不负担任何业务逻辑。业务逻辑层--负责系统领域业务的处理,负责逻辑性数据的生成、处理及转换。对流入的逻辑性数据的正确性及有效性负责,对流出的逻辑性数据及用户性数据不负责,对数据的呈现样式不负责。表示层-—负责接收用户的输入、将输出呈现给用户以及访问安全性验证。对流入的数据的正确性和有效性负责,对呈现样式负责,对流出的数据正确性不负责,但负责在数据不正确时给出相应的异常信息。模块划分及交互设计:综合以上分析,可在宏观上将整个系统分为一下几个模块:实体类模块-—一组实体类的集合,负责整个系统中数据的封装及传递。数据访问层接口族——一组接口的集合,表示数据访问层的接口。业务逻辑层接口族--一组接口的集合,表示业务逻辑层的接口。数据访问层模块——一组类的集合,完成数据访问层的具体功能,实现数据访问层接口族。业务逻辑层模块——一组类的集合,完成业务逻辑层的具体功能,实现业务逻辑层接口族。表示层模块——程序及可视元素的集合,负责完成表示层的具体功能。IoC容器模块——负责依赖注入的实现。辅助类模块——完成全局辅助性功能。各模块见交互关系如下:

图1这篇中理论比较多,但是它是整个架构的基础,可以帮助朋友们对将要实现的项目架构及要遵循的原则有一个整体的了解.当然,在后续文章中,将主要讨论Demo项目的实际开发过程,那时,这些思想和理论性的东西将得到体现。实体类是现实实体在计算机中的表示。它贯穿于整个架构,负担着在各层次及模块间传递数据的职责。一般来说,实体类可以分为“贫血实体类”和“充血实体类”,前者仅仅保存实体的属性,而后者还包含一些实体间的关系与逻辑.我们在这个Demo中用的实体类将是“贫血实体类"。ﻫﻫ

大多情况下,实体类和数据库中的表(这里指实体表,不包括表示多对多对应的关系表)是一一对应的,但这并不是一个限制,在复杂的数据库设计中,有可能出现一个实体类对应多个表,或者交叉对应的情况。在本文的Demo中,实体类和表是一一对应的,并且实体类中的属性和表中的字段也是对应的。

在看实体类的代码前,先看一下系统的工程结构。

如上图所示,在初始阶段,整个系统包括6个工程,它们的职责是这样的:ﻫ

Web—-表示层

Entity——存放实体类

Factory——存放和依赖注入及IoC相关的类

IBLL——存放业务逻辑层接口族ﻫ

IDAL-—存放数据访问层接口族ﻫ

Utility--存放各种工具类及辅助类

这只是一个初期架构,主要是将整个系统搭一个框架,在后续开发中,将会有其他工程被陆陆续续添加进来.

我们的实体类将放在Entity工程下,这里包括三个文件:AdminInfo.cs,MessageInfo。cs,CommentInfo。cs,分别是管理员实体类、留言实体类和评论实体类。具体代码如下:

AdminInfo。cs:

1using

System;

2

3namespace

NGuestBook.Entity

4{ﻫ

///

<summary>

///

实体类—管理员ﻫ

7

///

</summary>

8

[Serializable]ﻫ

9

public

class

AdminInfoﻫ10

11

private

int

id;

12

private

string

name;

13

private

string

password;

1415

public

int

IDﻫ16

{

17

get

return

this.id;

}

18

set

{

this。id

=

value;

}ﻫ19

}ﻫ2021

public

string

Name

22

23

get

return

this.name;

24

set

{

this.name

value;

}

25

}ﻫ2627

public

string

Passwordﻫ28

29

get

return

this.password;

}ﻫ30

set

{

this.password

value;

}

31

}ﻫ32

33}

34

MessageInfo.cs:

1using

System;

3namespace

NGuestBook。Entity

4{

5

///

〈summary>

6

///

实体类-留言ﻫ

///

〈/summary〉

8

[Serializable]

9

public

class

MessageInfoﻫ10

11

private

int

id;

12

private

string

guestName;

13

private

string

guestEmail;

14

private

string

content;

15

private

DateTime

time;ﻫ16

private

string

reply;ﻫ17

private

string

isPass;ﻫ1819

public

int

IDﻫ20

{

21

get

return

this.id;

}ﻫ22

set

{

this.id

value;

}

23

}

2425

public

string

GuestNameﻫ26

{

27

get

return

this.guestName;

}ﻫ28

set

this.guestName

=

value;

}ﻫ29

}ﻫ3031

public

string

GuestEmailﻫ32

{ﻫ33

get

{

return

this.guestEmail;

}ﻫ34

set

this.guestEmail

value;

}

35

}ﻫ3637

public

string

Contentﻫ38

{ﻫ39

get

{

return

this。content;

}ﻫ40

set

this.content

=

value;

41

4243

public

DateTime

Time

44

{ﻫ45

get

return

this。time;

}ﻫ46

set

{

this.time

=

value;

47

}ﻫ4849

public

string

Replyﻫ50

51

get

return

this。reply;

52

set

{

this.reply

=

value;

53

}ﻫ5455

public

string

IsPassﻫ56

57

get

{

return

this.isPass;

}ﻫ58

set

{

this.isPass

=

value;

}

59

}ﻫ60

}

61}ﻫ62

CommentInfo.cs:

1using

System;ﻫ

2

3namespace

NGuestBook。Entity

4{ﻫ

///

〈summary>

6

///

实体类-评论ﻫ

7

///

〈/summary〉

8

[Serializable]

9

public

class

CommentInfoﻫ10

{ﻫ11

private

int

id;ﻫ12

private

string

content;

13

private

DateTime

time;ﻫ14

private

int

message;ﻫ1516

public

int

ID

17

{ﻫ18

get

return

this.id;

}ﻫ19

set

this.id

value;

20

}

2122

public

string

Contentﻫ23

{ﻫ24

get

return

this.content;

25

set

{

this.content

value;

}

26

2728

public

DateTime

Timeﻫ29

30

get

return

this.time;

}ﻫ31

set

{

this.time

=

value;

}ﻫ32

}

3334

public

int

Message

35

{ﻫ36

get

return

this.message;

37

set

{

this。message

=

value;

38

}ﻫ39

40}ﻫ41

大家可以看出,实体类的代码很简单,仅仅是负责实体的表示和数据的传递,不包含任何逻辑性内容。下篇将介绍接口的设计。接下来,将进行接口的设计。这里包括数据访问层接口和业务逻辑层接口.在分层架构中,接口扮演着非常重要的角色,它不但直接决定了各层中的各个操作类需要实现何种操作,而且它明确了各个层次的职责。接口也是系统实现依赖注入机制不可缺少的部分。

本项目的接口设计将按如下顺序进行:ﻫ

1.首先由前文的需求分析,列出主要的UI部分.

2.分析各个UI需要什么业务逻辑支持,从而确定业务逻辑层接口。ﻫ

3。分析业务逻辑层接口需要何种数据访问操作,从而确定数据访问层接口。ﻫ

另外,为保证完全的面向对象特性,接口之间的数据传递主要靠实体类或实体类集合,禁止使用DataTable等对象传递数据。

由需求分析,列出主要UI

需求分析部分,请参看基于。NET平台的分层架构实战(二)——需求分析与数据库设计。有需求分析,可以列出系统中主要应包括以下UI:ﻫ

UI01——主页面,列出全部的留言及相应评论,支持分页显示.留言按发表时间逆序显示,评论紧跟在相应留言下.管理员可以通过相应链接对留言执行通过验证、删除、回复以及对评论进行删除操作。游客可通过相应连接进入发表留言评论页面。ﻫ

UI02—-发表留言页面,供游客发表新留言.

UI03--发表评论页面,供游客发表评论。

UI04-—回复留言页面,供管理员回复留言.

UI05—-管理员登录页面。

UI06-—管理员修改个人密码的页面。

UI07——超级管理员登录后的页面,主要提供管理员列表。可以通过相应链接将指定管理员删除。ﻫ

UI08—-添加新管理员的页面。

UI09-—操作成功完成后的跳转提示页面。

UI10——系统出现异常时显示友好出错信息的页面。ﻫ

由UI识别业务逻辑操作

UI01:按分页取得留言,按指定留言取得全部评论,将指定留言通过验证,将指定留言删除,将指定评论删除

UI02:添加新留言

UI03:添加新评论

UI04:回复留言

UI05:管理员登录ﻫ

UI06:修改管理员密码ﻫ

UI07:取得全部管理员信息,删除管理员ﻫ

UI08:添加新管理员ﻫ

经过整理,可得以下接口操作:

IAdminBLL:Add(添加管理员),Remove(删除管理员),ChangePassword(修改管理员密码),Login(管理员登录),GetAll(取得全部管理员)

IMessageBLL:Add(添加留言),Remove(删除留言),Revert(回复留言),Pass(将留言通过验证),GetByPage(按分页取得留言)ﻫ

ICommentBLL:Add(添加评论),Remove(删除评论),GetByMessage(按留言取得全部评论)

这三个接口文件都放在IBLL工程下,具体代码如下:

ﻫIAdminBLL.cs:

1using

System;ﻫ

2using

System.Collections.Generic;ﻫ

3using

System.Text;

4using

NGuestBook。Entity;ﻫ

5

6namespace

NGuestBook.IBLLﻫ

7{

8

///

〈summary>

9

///

业务逻辑层接口—管理员ﻫ10

///

〈/summary〉11

public

interface

IAdminBLLﻫ12

{

13

///

<summary〉14

///

添加管理员

15

///

</summary〉16

///

〈param

name=”admin">新管理员实体类</param〉17

///

<returns>是否成功</returns>18

bool

Add(AdminInfo

admin);ﻫ1920

///

〈summary>21

///

删除管理员ﻫ22

///

</summary>23

///

<param

name="id”〉欲删除的管理员的ID</param>24

///

<returns>是否成功〈/returns>25

bool

Remove(int

id);

2627

///

〈summary>28

///

修改管理员密码

29

///

</summary>30

///

<param

name=”id”>欲修改密码的管理员的ID</param>31

///

〈param

name="password">新密码〈/param〉32

///

<returns〉是否成功</returns>33

bool

ChangePassword(int

id,string

password);

3435

///

<summary〉36

///

管理员登录

37

///

</summary>38

///

〈param

name=”name"〉管理员登录名〈/param〉39

///

<param

name=”password">管理员密码〈/param>40

///

〈returns〉如果登录成功,则返回相应管理员的实体类,否则返回null</returns>41

AdminInfo

Login(string

name,string

password);ﻫ4243

///

<summary〉44

///

取得全部管理员信息ﻫ45

///

</summary>46

///

<returns〉管理员实体类集合</returns〉47

IList〈AdminInfo>

GetAll();

48

}ﻫ49}ﻫIMessageBLL.cs:

1using

System;

2using

System.Collections。Generic;

3using

System。Text;

4using

NGuestBook.Entity;

6namespace

NGuestBook.IBLLﻫ

7{

8

///

〈summary〉

///

业务逻辑层接口—留言ﻫ10

///

</summary>11

public

interface

IMessageBLLﻫ12

{ﻫ13

///

<summary>14

///

添加留言ﻫ15

///

〈/summary>16

///

〈param

name=”message">新留言实体类〈/param>17

///

<returns>是否成功〈/returns>18

bool

Add(MessageInfo

message);ﻫ1920

///

〈summary〉21

///

删除留言ﻫ22

///

</summary>23

///

<param

name="id"〉欲删除的留言的ID</param>24

///

<returns>是否成功</returns>25

bool

Remove(int

id);

2627

///

〈summary>28

///

回复留言ﻫ29

///

</summary>30

///

〈param

name="id”〉要回复的留言的ID</param>31

///

<param

name=”reply">回复信息</param〉32

///

<returns>是否成功〈/returns>33

bool

Revert(int

id,

string

reply);ﻫ3435

///

<summary〉36

///

将留言通过验证

37

///

〈/summary>38

///

<param

name=”id">通过验证的留言的ID</param>39

///

<returns〉是否成功</returns〉40

bool

Pass(int

id);ﻫ4142

///

<summary〉43

///

按分页取得留言信息ﻫ44

///

〈/summary〉45

///

〈param

name=”pageSize"〉每页显示几条留言〈/param〉46

///

<param

name="pageNumber"〉当前页码</param>47

///

<returns>留言实体类集合</returns〉48

IList〈MessageInfo>

GetByPage(int

pageSize,int

pageNumber);ﻫ49

}ﻫ50}

ICommentBLL。cs

1using

System;

2using

System。Collections。Generic;

3using

System.Text;

4using

NGuestBook.Entity;ﻫ

6namespace

NGuestBook.IBLL

7{

8

///

〈summary>

9

///

业务逻辑层接口-评论

10

///

</summary>11

public

interface

ICommentBLLﻫ12

{ﻫ13

///

<summary〉14

///

添加评论

15

///

</summary>16

///

<param

name="comment”〉新评论实体类</param>17

///

<returns>是否成功</returns>18

bool

Add(CommentInfo

comment);

1920

///

〈summary〉21

///

删除评论ﻫ22

///

〈/summary〉23

///

〈param

name="id"〉欲删除的评论的ID</param〉24

///

<returns〉是否成功</returns>25

bool

Remove(int

id);

2627

///

<summary〉28

///

取得指定留言的全部评论ﻫ29

///

</summary>30

///

<param

name="messageId”>指定留言的ID</param〉31

///

〈returns>评论实体类集合</returns〉32

IList〈CommentInfo>

GetByMessage(int

messageId);

33

}ﻫ34}ﻫ

由业务逻辑确定数据访问操作

IAdminBLL需要的数据访问操作:插入管理员,删除管理员,更新管理员信息,按ID取得管理员信息,按登录名与密码取得管理员,取得全部管理员

IMessageBLL需要的数据访问操作:插入留言,删除留言,更新留言信息,按ID取得留言信息,按分页取得留言ﻫ

ICommentBLL需要的数据访问操作:插入评论,删除评论,按留言取得全部评论

另外,添加管理员时需要验证是否存在同名管理员,所以需要添加一个“按登录名取得管理员”.

对以上操作进行整理,的如下接口操作:

IAdminDAL:Insert,Delete,Update,GetByID,GetByNameAndPassword,GetAllﻫ

IMessageDAL:Insert,Delete,Update,GetByID,GetByPageﻫ

ICommentDAL:Insert,Delete,GetByMessage

这三个接口文件放在IDAL工程下,具体代码如下:ﻫﻫIAdminDAL。cs:

1using

System;ﻫ

2using

System.Collections。Generic;

3using

System.Text;ﻫ

4using

NGuestBook.Entity;ﻫ

5

6namespace

NGuestBook.IDAL

7{ﻫ

8

///

〈summary>

///

数据访问层接口-管理员ﻫ10

///

</summary〉11

public

interface

IAdminDAL

12

13

///

<summary>14

///

插入管理员

15

///

</summary〉16

///

<param

name="admin">管理员实体类</param〉17

///

<returns〉是否成功〈/returns〉18

bool

Insert(AdminInfo

admin);ﻫ1920

///

<summary>21

///

删除管理员ﻫ22

///

</summary〉23

///

〈param

name="id">欲删除的管理员的ID</param>24

///

〈returns>是否成功</returns>25

bool

Delete(int

id);

2627

///

<summary〉28

///

更新管理员信息ﻫ29

///

</summary>30

///

〈param

name="admin">管理员实体类〈/param〉31

///

〈returns>是否成功</returns〉32

bool

Update(AdminInfo

admin);ﻫ3334

///

<summary〉35

///

按ID取得管理员信息ﻫ36

///

</summary〉37

///

<param

name=”id">管理员ID</param〉38

///

<returns〉管理员实体类</returns〉39

AdminInfo

GetByID(int

id);

4041

///

〈summary〉42

///

按管理员名取得管理员信息

43

///

〈/summary>44

///

<param

name="name"〉管理员名〈/param〉45

///

<returns〉管理员实体类</returns〉46

AdminInfo

GetByName(string

name);

4748

///

<summary>49

///

按用户名及密码取得管理员信息

50

///

</summary>51

///

<param

name="name”>用户名</param>52

///

<param

name=”password">密码</param>53

///

<returns>管理员实体类,不存在时返回null</returns>54

AdminInfo

GetByNameAndPassword(string

name,string

password);

5556

///

〈summary>57

///

取得全部管理员信息

58

///

〈/summary>59

///

<returns〉管理员实体类集合</returns〉60

IList<AdminInfo>

GetAll();ﻫ61

62}

IMessageDAL.cs:

1using

System;

2using

System.Collections。Generic;

3using

System.Text;ﻫ

4using

NGuestBook。Entity;

5

6namespace

NGuestBook.IDAL

7{ﻫ

///

<summary〉

9

///

数据访问层接口-留言ﻫ10

///

</summary〉11

public

interface

IMessageDALﻫ12

13

///

〈summary>14

///

插入留言

15

///

〈/summary〉16

///

<param

name="message">留言实体类</param>17

///

〈returns>是否成功〈/returns>18

bool

Insert(MessageInfo

message);

1920

///

<summary>21

///

删除留言

22

///

</summary>23

///

〈param

name=”id">欲删除的留言的ID</param〉24

///

〈returns〉是否成功〈/returns〉25

bool

Delete(int

id);

2627

///

<summary〉28

///

更新留言信息ﻫ29

///

</summary〉30

///

<param

name="message”〉留言实体类〈/param>31

///

〈returns〉是否成功〈/returns>32

bool

Update(MessageInfo

message);

3334

///

<summary〉35

///

按ID取得留言信息ﻫ36

///

</summary>37

///

〈param

name="id”〉留言ID〈/param〉38

///

<returns>留言实体类〈/returns>39

MessageInfo

GetByID(int

id);ﻫ4041

///

<summary〉42

///

按分页取得留言信息ﻫ43

///

</summary>44

///

〈param

name="pageSize"〉每页显示几条留言</param〉45

///

〈param

name="pageNumber"〉当前页码</param>46

///

<returns>留言实体类集合</returns>47

IList<MessageInfo>

GetByPage(int

pageSize,int

pageNumber);

48

}

49}ﻫICommentDAL。cs:

1using

System;

2using

System.Collections.Generic;

3using

System.Text;

4using

NGuestBook.Entity;ﻫ

5

6namespace

NGuestBook.IDALﻫ

7{

///

〈summary>

9

///

数据访问层接口-评论ﻫ10

///

</summary>11

public

interface

ICommentDALﻫ12

13

///

<summary>14

///

插入评论

15

///

〈/summary>16

///

〈param

name="comment"〉评论实体类〈/param>17

///

〈returns>是否成功</returns〉18

bool

Insert(CommentInfo

comment);

1920

///

〈summary〉21

///

删除评论ﻫ22

///

〈/summary>23

///

<param

name=”id”〉欲删除的评论的ID</param>24

///

〈returns>是否成功</returns〉25

bool

Delete(int

id);

2627

///

〈summary〉28

///

取得指定留言的全部评论

29

///

〈/summary〉30

///

〈param

name=”messageId”>指定留言的ID</param>31

///

<returns〉评论实体类集合</returns>32

IList〈CommentInfo〉

GetByMessage(int

messageId);

33

34}我们设计的分层架构,层与层之间应该是松散耦合的。因为是单向单一调用,所以,这里的“松散耦合”实际是指上层类不能具体依赖于下层类,而应该依赖于下层提供的一个接口.这样,上层类不能直接实例化下层中的类,而只持有接口,至于接口所指变量最终究竟是哪一个类,则由依赖注入机制决定。ﻫﻫ

之所以这样做,是为了实现层与层之间的“可替换”式设计,例如,现在需要换一种方式实现数据访问层,只要这个实现遵循了前面定义的数据访问层接口,业务逻辑层和表示层不需要做任何改动,只需要改一下配置文件系统即可正常运行.另外,基于这种结构的系统,还可以实现并行开发。即不同开发人员可以专注于自己的层次,只有接口被定义好了,开发出来的东西就可以无缝连接。ﻫ

在J2EE平台上,主要使用Spring框架实现依赖注入。这里,我们将自己做一个依赖注入容器。

依赖注入的理论基础是AbstractFactory设计模式,这里结合具体实例简单介绍一下。ﻫ

上图以数据访问层为例,展示了AbstractFactory模式的应用。如图,现假设有针对Access和SQLServer两种数据库的数据访问层,它们都实现了数据访问层接口。每个数据访问层有自己的工厂,所有工厂都实现自IDALFactory接口。而客户类(这里就是业务逻辑层类)仅与工厂接口、数据访问层接口耦合,而与具体类无关,这样,只要通过配置文件确定实例化哪个工厂,就可以得到不同的数据访问层.

然而,这种设计虽然可行,但是代码比较冗余,因为这样需要为数据访问层的每一个实现编写一个工厂,业务逻辑层也一样。在以前,我们毫无办法,但是,。NET平台引入的反射机制,给我们提供了一种解决方案。使用反射,每个层只需要一个工厂,然后通过从配置文件中读出程序集的名称,动态加载相应类。另外,为了提高依赖注入机制的效率,这里引入缓存机制。下面来看具体实现。

配置

首先,需要在Web工程的Web.config文件的〈appSettings〉节点下添加如下两个项:

<addkey="DAL"value="”/>ﻫ

〈addkey=”BLL"value=""/〉

这两个配置选项分别存储要应用的数据访问和也业务逻辑层的程序集名称。value目前是空,是因为目前还没有各个层次的具体实现。

实现缓存操作辅助类

为实现缓存操作,我们将缓存操作封装成一个辅助类,放在Utility工程下,具体代码如下:

ﻫCacheAccess.cs:

封装依赖注入代码

因为很多依赖注入代码非常相似,为了减少重复性代码,我们将可复用的代码先封装在一个类中。具体代码如下(这个类放在Factory工程下):

DependencyInjector.cs:

1using

System;

2using

System。Web;ﻫ

3using

System.Web.Caching;ﻫ

4

5namespace

NGuestBook.Utilityﻫ

6{

7

///

<summary〉

///

辅助类,用于缓存操作ﻫ

9

///

〈/summary〉10

public

sealed

class

CacheAccess

11

{ﻫ12

///

<summary〉13

///

将对象加入到缓存中ﻫ14

///

〈/summary〉15

///

<param

name=”cacheKey"〉缓存键</param〉16

///

<param

name="cacheObject"〉缓存对象</param>17

///

〈param

name="dependency"〉缓存依赖项</param〉18

public

static

void

SaveToCache(string

cacheKey,

object

cacheObject,

CacheDependency

dependency)ﻫ19

20

Cache

cache

HttpRuntime。Cache;

21

cache。Insert(cacheKey,

cacheObject,

dependency);

22

}ﻫ2324

///

<summary>25

///

从缓存中取得对象,不存在则返回null

26

///

〈/summary>27

///

〈param

name="cacheKey"〉缓存键</param>28

///

<returns>获取的缓存对象</returns>29

public

static

object

GetFromCache(string

cacheKey)ﻫ30

{ﻫ31

Cache

cache

=

HttpRuntime。Cache;ﻫ3233

return

cache[cacheKey];ﻫ34

35

}ﻫ36}

1using

System;ﻫ

2using

System。Configuration;ﻫ

3using

System.Reflection;ﻫ

4using

System.Web;ﻫ

5using

System.Web.Caching;

6using

NGuestBook.Utility;ﻫ

7

8namespace

NGuestBook。Factoryﻫ

9{ﻫ10

///

〈summary〉11

///

依赖注入提供者ﻫ12

///

使用反射机制实现ﻫ13

///

</summary>14

public

sealed

class

DependencyInjectorﻫ15

{ﻫ16

///

<summary>17

///

取得数据访问层对象ﻫ18

///

首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象

19

///

</summary〉20

///

〈param

name=”className">数据访问类名称</param〉21

///

<returns>数据访问层对象〈/returns〉22

public

static

object

GetDALObject(string

className)

23

{ﻫ24

///

〈summary>25

///

取得数据访问层名称,首先检查缓存,不存在则到配置文件中读取

26

///

缓存依赖项为Web.Config文件

27

///

〈/summary>28

object

dal

=

CacheAccess.GetFromCache(”DAL");ﻫ29

if

(dal

==

null)

30

{ﻫ31

CacheDependency

fileDependency

=

new

CacheDependency(HttpContext.Current。Server.MapPath(”Web.Config"));

32

dal

=

ConfigurationManager.AppSettings["DAL”];ﻫ33

CacheAccess.SaveToCache(”DAL",

dal,

fileDependency);

34

}

3536

///

<summary>37

///

取得数据访问层对象ﻫ38

///

〈/summary>39

string

dalName

=

(string)dal;ﻫ40

string

fullClassName

=

dalName

+

"。"

+

className;

41

object

dalObject

=

CacheAccess.GetFromCache(className);ﻫ42

if

(dalObject

==

null)ﻫ43

44

CacheDependency

fileDependency

=

new

CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));

45

dalObject

Assembly。Load(dalName)。CreateInstance(fullClassName);ﻫ46

CacheAccess.SaveToCache(className,

dalObject,

fileDependency);ﻫ47

}ﻫ4849

return

dalObject;ﻫ50

5152

///

〈summary〉53

///

取得业务逻辑层对象

54

///

首先检查缓存中是否存在,如果不存在,则利用反射机制返回对象ﻫ55

///

〈/summary〉56

///

<param

name=”className">业务逻辑类名称</param>57

///

<returns〉业务逻辑层对象</returns>58

public

static

object

GetBLLObject(string

className)

59

{

60

///

<summary>61

///

取得业务逻辑层名称,首先检查缓存,不存在则到配置文件中读取ﻫ62

///

缓存依赖项为Web。Config文件ﻫ63

///

〈/summary>64

object

bll

=

CacheAccess.GetFromCache(”BLL");ﻫ65

if

(bll

==

null)

66

{

67

CacheDependency

fileDependency

=

new

CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));

68

bll

ConfigurationManager.AppSettings[”BLL"];ﻫ69

CacheAccess.SaveToCache("BLL",

bll,

fileDependency);

70

}

7172

///

<summary>73

///

取得业务逻辑层对象

74

///

</summary>75

string

bllName

=

(string)bll;ﻫ76

string

fullClassName

=

bllName

”."

+

className;

77

object

bllObject

CacheAccess。GetFromCache(className);

78

if

(bllObject

==

null)

79

{ﻫ80

CacheDependency

fileDependency

=

new

CacheDependency(HttpContext。Current.Server.MapPath("Web.Config"));

81

bllObject

Assembly.Load(bllName).CreateInstance(fullClassName);

82

CacheAccess.SaveToCache(className,

bllObject,

fileDependency);ﻫ83

}ﻫ8485

return

bllObject;

86

87

}ﻫ88}

实现工厂

下面使用两个辅助类,实现数据访问层工厂和业务逻辑层工厂.ﻫﻫDALFactory。cs

1using

System;ﻫ

2using

NGuestBook.IDAL;ﻫ

3

4namespace

NGuestBook.Factoryﻫ

5{

6

///

〈summary>

7

///

数据访问层工厂,用于获取相应的数据访问层对象

8

///

使用Abstract

Factory设计模式+Facace设计模式+反射机制+缓存机制设计

9

///

</summary>10

public

sealed

class

DALFactoryﻫ11

{

12

///

<summary>13

///

获取管理员数据访问层对象ﻫ14

///

</summary>15

///

<returns>管理员数据访问层对象〈/returns〉16

public

static

IAdminDAL

CreateAdminDAL()ﻫ17

{ﻫ18

return

(IAdminDAL)DependencyInjector.GetDALObject("AdminDAL”);ﻫ19

}ﻫ2021

///

〈summary>22

///

获取留言数据访问层对象

23

///

</summary〉24

///

<returns>留言数据访问层对象</returns〉25

public

static

IMessageDAL

CreateMessageDAL()

26

{ﻫ27

return

(IMessageDAL)DependencyInjector.GetDALObject("MessageDAL");ﻫ28

}ﻫ2930

///

<summary>31

///

获取评论数据访问层对象

32

///

〈/summary>33

///

<returns>评论数据访问层对象</returns〉34

public

static

ICommentDAL

CreateCommentDAL()

35

36

return

(ICommentDAL)DependencyInjector.GetDALObject("CommentDAL”);ﻫ37

}

38

}

39}ﻫBLLFactory.cs

1using

System;

2using

NGuestBook。IBLL;

3

4namespace

NGuestBook。Factoryﻫ

5{ﻫ

6

///

<summary〉

7

///

业务逻辑层工厂,用于获取相应的业务逻辑层对象

8

///

使用Abstract

Factory设计模式+Facace设计模式+反射机制+缓存机制设计ﻫ

9

///

</summary>10

public

sealed

class

BLLFactoryﻫ11

{ﻫ12

///

<summary>13

///

获取管理员业务逻辑层对象ﻫ14

///

</summary>15

///

〈returns〉管理员业务逻辑层对象〈/returns>16

public

static

IAdminBLL

CreateAdminBLL()

17

{ﻫ18

return

(IAdminBLL)DependencyInjector.GetBLLObject(”AdminBLL”);

19

}ﻫ2021

///

<summary〉22

///

获取留言业务逻辑层对象ﻫ23

///

</summary>24

///

<returns〉留言业务逻辑层对象〈/returns>25

public

static

IMessageBLL

CreateMessageBLL()

26

27

return

(IMessageBLL)DependencyInjector。GetBLLObject("MessageBLL”);

28

}ﻫ2930

///

<summary>31

///

获取评论业务逻辑层对象

32

///

〈/summary〉33

///

〈returns>评论业务逻辑层对象</returns>34

public

static

ICommentBLL

CreateCommentBLL()

35

{ﻫ36

return

(ICommentBLL)DependencyInjector.GetBLLObject("CommentBLL");ﻫ37

}

38

}

39}经过上面篇文章的介绍,整个系统的框架算是基本搭建完了,下面,我们要具体实现各个层次。关于数据访问层的实现,我准备讨论三种实现方式,这一篇文章讨论第一种:Access+动态生成SQL。

顾名思义,这种实现将使用Access作为后台数据库,而操作方式也是最基本的使用SQL命令.ﻫ

在具体编写实现代码之前,我们需要做一些准备工作:

第一步,我们要将Access数据库搭建完成,具体做法如下.

在Web工程下新建一个文件夹,命名为AccessData,并在其中新建一个mdb文件(即Access数据库文件),按照前面介绍过的数据库设计构架,将数据表及表间关系建好,这里不再赘述。

第二步,我们要进行一些配置。

打开Web工程下的Web.config文件,在其中的appSettings节点下,添加如下键值:

<addkey="AccessConnectionString"value="Provider=Microsoft.Jet。OLEDB.4。0;DataSource={DBPath}"/>ﻫ

<addkey="AccessPath”value="~/AccessData/AccessDatabase.mdb"/>ﻫ

第一条为Access的连接字符串,第二条为Access数据库文件的路径,其中“~”表示网站根目录。

第三步,新建一个工程.ﻫ

我们要新建一个工程AccessDAL,用来存放Access数据访问层的代码。ﻫ

准备工作做完了,现在来实现具体的代码.ﻫ

1.编写数据访问助手类

因为很多数据访问操作流程很相似,所以,这里将一些可复用的代码抽取出来,编写成助手类,以此减少代码量,提高代码复用性.ﻫ

这个助手类放在AccessDAL下,叫AccessDALHelper,主要负责Access数据库的访问。它包括三个方法:ﻫ

GetConnectionString:从配置文件中读取配置项,组合成连接字符串.

ExecuteSQLNonQuery:执行指定SQL语句,不返回任何值,一般用于Insert,Delete,Update命令.

ExecuteSQLDataReader:执行SQL语句返回查询结果,一般用于Select命令。ﻫ

具体代码如下:

ﻫAccessDALHelper。cs:ﻫ

2。实现具体的数据访问操作类ﻫ

因为前面已经定义了数据访问层接口,所以实现数据访问操作类就是很机械的工作了。下面仅以Admin的数据访问操作类为例:ﻫﻫAdminDAL:

1using

System;

2using

System.Web;

3using

System。Web。Caching;ﻫ

4using

System.Configuration;

5using

System.Data;ﻫ

6using

System.Data.OleDb;ﻫ

7using

NGuestBook.Utility;ﻫ

9namespace

NGuestBook.AccessDAL

10{

11

///

<summary>12

///

Access数据库操作助手ﻫ13

///

〈/summary〉14

public

sealed

class

AccessDALHelper

15

{ﻫ16

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论