.NET平台的分层架构与设计模式应用研究毕业设计l论文- 副本

更新时间:2024-05-27 02:59:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

广东科学技术职业学院

计算机工程技术学院(软件学院)

毕 业 设 计

题目:.NET平台的分层架构与设计模式应用研究

专业: 软件技术 学生姓名: 张炳东

班级:08软件开发3班 学号: 0104080745

指导教师姓名: 李建青 职称: 讲师

2011年2月

广东科学技术职业学院计算机工程技术学院 ( 软件技术 )专业毕业设计任务书

填表日期: 年 月 日 填表人:

课题 .NET平台的分层架构与设计模式应用研究 李建青 职称 讲师 课题小组人数 5 班别 08软开3 指导教师 开题 情 况 设 计 任 务 及 指 标 学生 在该设计中具体完成的工作 审核意见 指导教师(签章): 主任(签章): 年 月 日 年 月 日

指导教师评语: 指导教师评分: 指导教师签名: 年 月 日 答辩委员会对毕业设计的评语和成绩评定决议: 答辩委员会: (签章) 答辩委员会评分: 主任: 年 月 日 院长评分决议: 院长: (签章) 年 月 日 .NET平台的分层架构与设计模式应用研究

一、绪论........................................................................................................................................... 6

1.1 B/S系统概述 ...................................................................................................................... 6 1.2 分层架构概述 ................................................................................................................... 7 1.3 设计模式概述 .................................................................................................................... 8 1.4 研究背景 ............................................................................................................................ 9

1.4.1 .NET平台分层架构的现状及可研究性 ................................................................ 9 1.4.2 研究目的 ............................................................................................................... 10 1.4.3 研究方法 ............................................................................................................. 10

二、关键性原则及总体架构......................................................................................................... 11

2.1 关键性原则..................................................................................................................... 11

2.1.1 分层架构逐渐调用原则及单向调用原则 ......................................................... 11 2.1.2 单一职责原则 ..................................................................................................... 11 2.1.3 开放-封闭原则 ................................................................................................... 11 2.1.4 依赖倒转原则 ..................................................................................................... 12 2.1.5 迪米特原则 ......................................................................................................... 12 2.2 总体架构 ........................................................................................................................ 12

2.2.1层次划分 .............................................................................................................. 12 2.2.2 职责划分 ............................................................................................................. 12 2.2.3 模块划分及交互设计 ......................................................................................... 13

三、关键性构件及各层次实现..................................................................................................... 14

3.1 实体的识别及数据库设计............................................................................................. 14

3.1.1识别实体 .............................................................................................................. 14 3.1.2 数据库设计 ......................................................................................................... 14 3.2 实体类设计..................................................................................................................... 17

3.2.1 实体类概述、作用及设计目标 ......................................................................... 17 3.2.2 实体类的设计方案及其比较 ............................................................................. 18 3.2.3 实体类的实现 ..................................................................................................... 18 3.3 接口设计 ........................................................................................................................ 18

3.3.1 接口概述及其作用 ............................................................................................. 18 3.3.2 数据访问层接口的设计 ..................................................................................... 19 3.3.3 业务逻辑层接口的设计 ..................................................................................... 20

四、三层架构中常用的设计模式................................................................................................. 21

4.1 依赖注入与控制反转 ..................................................................................................... 21 4.2 Abstract Factory模式在三层架构的应用 ................................................................ 23 4.3 三层架构中的外观模式(Facade) ............................................................................. 24 致谢 ................................................................................................................................................ 25 [参考文献] ...................................................................................................................................... 25 附录一:代码摘要 ......................................................................................................................... 26

用户实体类:BookStoreModels.Users.cs ............................................................................. 26 用户数据访问层接口:BookStoreIDAL.IUsers.cs ............................................................... 28 用户业务逻辑层接口:BookStoreBLL.Users.cs .................................................................. 30

抽象工厂类:BookSoreDALFactory.AbstractDALFactory.cs .............................................. 33

[摘 要] “编程是一门技术,更加是一门艺术[6]”。在传统的系统设计中,

将对数据库的访问、业务逻辑及可视元素等代码混编。这样的不但代码风格不美观,所写的程序更是可读性差,耦合度高,不容易维护,灵活性差,不容易扩展,更谈不上复用。为了解决这个问题,有人提出了N层架构思想,即将各个功能块明确分开,放置在独立的层中,各层之间通过协作来完成整体功能。

本文只是以网上购物为例,结合分层架构中常用的设计模式对.NET平台上的分层架构进行深入的研究和探讨,以期其总结出的理论能给.NET平台的开发人员一个指导性作用。

[关键词] .NET,分层架构,设计模式

[Abstract]”Programing is a technology ,I consider it as an art

[6]” .In traditional system designing , Database Access , Business Logic and visual elements are usually combined together .In this case , not only the code written in the program is unreadable and high coupling ,but also is not easy to maintain and extend ,inflexibility and much less to reconstruction . To solve this issue , Multi-Layers Architecture was proposed . In this architecture , different functions are separated into different layers , which can cooperate with each other to achieve the whole function .

Taken a system of shopping online for example , this paper combine with some design patterns in common usage on Multi-Layer Architecture to present a deep research to the Multi-Layer Architecture on .NET platform ,and hopes to get some useful conclusions to guide the developers on .NET platform.

[Key Words] .NET , Multi-Layer Architecture , Design Pattern

一、绪论

1.1 B/S系统概述

B/S结构(Browser/Server,浏览器/服务器模式),是WEB兴起后的一种网络结构模式,WEB浏览器是客户端最主要的应用软件。这种模式统一了客户端,将系统功能实现的核心部分集中到服务器上,简化了系统的开发、维护和使用。客户机上只要安装一个浏览器(Browser),如Netscape Navigator或Internet Explorer,服务器安装Oracle、Sybase、Informix或 SQL Server等数据库。浏览器通过Web Server 同数据库进行数据交互。

B/S结构图

在这种结构下,用户工作界面是通过WWW浏览器来实现,极少部分事务逻辑在前端(Browser)实现,但是主要事务逻辑在服务器端(Server)实现,形成所谓三层3-tier结构。相对于C/S结构属于“胖”客户端,需要在使用者电脑上安装相应的操作软件来说,B/S结构是属于一种“瘦”客户端,大多数或主要的业务逻辑都存在在服务器端,因此,B/S结构的系统可以在任何地方进行操作而不用安装任何专门的软件,只要有一台能上网的电脑就能使用,客户端零维护。系统的扩展非常容易。B/S结构系统的产生为系统面对无限未知用户提供了可能。当然,与C/S结构相比,B/S结构也存在着系统运行速度较慢,访问系统的

用户不可控的弱点。

以目前的技术看,局域网建立B/S结构的网络应用,并通过Internet/Intranet模式下数据库应用,相对易于把握、成本也是较低的。它是一次性到位的开发,能实现不同的人员,从不同的地点,以不同的接入方式(比如LAN,WAN,Internet/Intranet等)访问和操作共同的数据库;它能有效地保护数据平台和管理访问权限,服务器数据库也很安全。特别是在JAVA这样的跨平台语言出现之后,B/S架构管理软件更是方便、快捷、高效。 1.2 分层架构概述

在分解复杂的软件系统时,软件设计者用得最多的技术之一就是分层。在计算机本身的架构中,可以看到:到处都有分层的例子:不同的层从包含了操作系统调用的程序设计语言,到设备驱动程序和CPU指令集,再到芯片内部的各种逻辑门。网络互联中,FTP层架构在TCP之上,TCP架构在IP之上,IP又架构在以太网之上。当用分层的观点来考虑系统时,可以将各个子系统想像成按照“多层蛋糕”的形式来组织,每一层都依托在其下层之上。在这种组织方式下,上层使用了下层定义的各种服务,而下层对上层一无所知。另外,每一层对自己的上层隐藏其下层的细节。

多层架构的提出,是软件开发思想的一个重大进步。它的出现,在很大程度上解决了软件开发中的强耦合问题,也为编写代码清晰、可维护性良好的系统提供了思想基础。

Martin Fowler在《企业应用架构模式》一书中对分层架构的优势描述如下: ", 开发人员可以只关注整个架构中的其中一层 ", 可以很容易地用新的实现替代原有层次的实现 ", 可以降低层与层之间的依赖 ", 有利于标准化 ", 有利于各层逻辑的复用

概括来说,分层架构设计可以达到如下目的:分散关注,松散耦合,逻辑复用,标准定义。

当然,任何事物有利也有弊。分层架构的一大缺点就是降低了系统的性能,

因为本来直接完成的功能现在需要多次调用才能完成,自然使得性能下降。所以,分层架构可以说是以牺牲系统性能换取可维护性的手段。

可以看出,系统的性能和可维护性是一对矛盾,鱼和熊掌和难兼得,所以在使用分层架构设计系统时,要把握一个度,不能过于极端的强调性能或可维护性,而是应该根据系统的具体情况,取两者的折中。

1.3 设计模式概述

目前,软件设计模式尚处在迅速发展之中,越来越多的研究人员正在把注意力投向软件设计模式的研究。关于软件设计模式的研究工作主要在国外展开的,国内到目前为止对于软件设计模式的研究尚处在起步阶段。

设计模式这个概念最初产生于建筑行业。设计师(设计建筑物而不是计算机系统)意识到他们需要共享有关正确设计技术的想法。这些想法是在可以使设计师团体从分享经验和教训中获益的设计模式中形成的。设计模式在80 年代后期从建筑业进入计算机系统领域。面向对象(Object-oriented,OO)原则逐渐得到普及,而设计模式成为培育新的OO 追随者的最佳实践。

Richard Gamma 等(人们通常把他们称作 Gang of Four [GoF] )编著的《Design Patterns: Elements of Reusable Object-Oriented Software》一书使设计模式成为万众瞩目的焦点。随着设计模式逐渐普及,他们所涉及的领域就像“Ben and Jerry”效应那样也逐渐广泛起来。因此,它就是设计模式,和普通的OO 设计模式一样来源于GoF 的著作,但是现在包括了专为开发语言、应用服务器、行业合成等提供的设计模式。

设计模式通常根据一些公共特性而组合在一起。GoF 的著作把设计模式划分为三类:Creational、Behavioral 和Structural。用于J2EE 的设计模式通常划分为表现层(Presentation Tier)、业务逻辑层(Business Logic Tier)和集成层(Integration Tier)。这种分组方式可以使描述所有设计模式共享的公共细节更加轻松,或者使设计模式的分类和发现更加轻松。[4]

尽管设计模式本身并不要求一定用某种语言来实现,但脱离了具体的实现,就无法真正理解设计模式。GOF 的《设计模式》是经典之作,但毕竟距现在已经十几年了。这个期间开发平台已经进化了多代,很多新技术已经应用到编程中。

有些技术可以简化设计模式的实现,有些技术已经采用了设计模式。因此,设计模式必须针对所使用的编程语言和开发平台,一定要注意,不是将《设计模式》

中的例子转换为C#或者其他语言就等于知道如何实现设计模式了,而是要关注设计模式的精髓,并结合具体的语言特点完成其实现。

就.NET 而言,很多技术可以简化设计模式的实现,例如,采用反射技术实现工厂和采用委托技术实现模板方法等。另外,由于国情不同和业务的发展,使得设计模式的选择和运用更具有特殊性,特别是在业务变化频繁项目中的选择和运用。

1.4 研究背景

1.4.1 .NET平台分层架构的现状及可研究性

微软(Microsoft)公司的.NET平台凭借其先进的设计思想、丰富的类库、

强大的能力和完善的IDE及开发帮助文档获得了众多开发者的青睐。尤其在Web开发平台方面,ASP.NET凭借其完善的面向对象模型和独树一帜的控件式开发方式将Web开发这一技术领域提高到一个前所未有的新境界。

然而,令人遗憾的是,到目前为止,仍缺少一个成熟的基于.NET平台的经

典分层架构体系。反观其竞争对手Java平台,从EJB到轻量级框架,基于J2EE平台的分层架构已相当成熟和完善。目前,基于.NET平台的分层架构一般都是模仿微软官方给出的分层范例——“.NET PetShop”。虽然“.NET PetShop”是一个经典的基于.NET平台的B/S系统分层架构示例,然而也有许多不足,如:

1.结构过于复杂,有点为分层而分层的感觉,对实际项目指导力不足。 2.实现方法单一。如数据访问层是使用的朴素实现,即手工组合参数,然后

动态生成SQL语句和调用存储过程。然而在实际中,可能有更多的实现方式,例如通过ORM实现,这就需要进一步讨论数据访问层的共性,从更高的抽象层次上对其进行理解和掌握,而不是仅仅把数据访问层看成一种具体的实现。

基于以上几点,可以看出,现在迫切需要形成一套理论,来指导.NET平台

上的分层架构开发,而不是让其仅仅停留在模仿阶段。

1.4.2 研究目的

本论文的研究目的,是力图通过对分层架构思想、设计模式、软件工程、.NET

平台以及Web2.0思想等论题的研究,寻找一种合理、简练、通用、易用、安全、具有良好的可维护性和可扩展性并且融入最新技术元素的基于.NET平台的分层架构模式。而且要通过一个完整的系统实例展现出来。

另外,设计模式也是本课题要讨论的话题之一。因为,做架构设计离不开设

计模式。文章中在用到设计模式的地方,进行与分层架构模型有关的讨论,并研究其在与.NET平台的结合中的特殊问题。 1.4.3 研究方法

本文是一个兼具理论与应用的课题,所以,在研究过程中,两方面都要涉及

到。基于此,我们对此课题采取的研究方法是:收集需求、提出方案、设计实现、验证效果。

首先,应该从整体到部分,对整个分层架构体系各个需求进行收集,明确各

部件的职责;然后,针对其职责,提出几种设计方案,并进行设计实现;最后,从耦合度、可扩展性、可维护性和性能等多方面对方案进行验证,提出对解决方案的评价。

为了避免脱离实际,在研究本课题的过程中,将逐步完成一个实际的系统,

而所有的理论,都将直接作用在此系统上,贯穿于一个完整的系统开发过程中,从而让理论在实践中得到检验。

本文研究的Demo将是一个网上购物系统,之所以选择网上购物系统,有以

下几点原因:

1.规模适中。网上购物系统的规模适中,既能起到示例的作用,又不会因为

太过复杂而影响进度。

2.业务逻辑熟悉。一般来讲,在做某个系统时,业务逻辑的设计要和领域专

家合作,因为一般情况下软件开发人员对其他领域的业务流程并不熟悉。而网上购物系统是我们常用的一种系统,大多数人对其业务逻辑非常熟悉。这样就可以免去在研究业务上耗费精力,而将主要经历放在架构的研究上。

二、关键性原则及总体架构

2.1 关键性原则

在软件开发技术的发展过程中,出现了很多优秀的思想与模式。这些思想和

模式凝结了无数程序设计人员的实践经验,是软件开发领域的精华。其中的很多思想,对分层架构设计也有着重要的指导作用,下面将列出一些在本课题研究中起着重要作用的指导思想和所设计的架构应遵循的原则。

2.1.1 分层架构逐渐调用原则及单向调用原则

现在约定将N层架构的各层依次编号为1、2、?、K、?、N-1、N,其中

层的编号越大,则越处在上层。那么,我们设计的架构应该满足以下两个原则: 1.第K(1

其中第一个原则,保证了依赖的逐层性,及整个架构的依赖是逐层向下的,而不能跨层依赖。第一个原则,则保证了依赖的单向性,及只能上层依赖底层,而不能底层反过来依赖上层。 2.1.2 单一职责原则

就一个类而言,应该仅有一个引起它变化的原因。软件设计真正要做的许多

内容,就是发现职责并把那些职责相互分离。如果你能够想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责,一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生是,设计会遭受到意想不到的破坏[2]。 2.1.3 开放-封闭原则

开放-封闭原则,是说软件实体(类、模块、函数等等)应该可以扩展(Open

for extension),但是不可修改(Closed for modification)。开放-封闭原则是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护、可扩展、可复用、灵活性好。开发人员应该仅对程序中呈现出频繁变化的那些部分做出抽象,然而。对于应用程序中的每个部分都刻意地进行抽象和抽象本身一样重要[2]。

具体到N层架构中,可以描述为:当K-1层有了一个新的具体实现时,它

应该可以在不修改K层的情况下,与K层无缝连接,顺利交互。 2.1.4 依赖倒转原则

依赖到转原则,A.高层模块不应该依赖底层模块。两个都应该依赖抽象;

B.抽象不应该依赖细节,细节应该依赖抽象[2]。如果不管高层模块还是底层模块都依赖于抽象,具体一点就是借口或抽象类,只要接口是稳定的,那么任何一个的更改都不用担心其他收到影响,这就使得无论高层模块还是底层模块都可以很容易地被复用[6]。 2.1.5 迪米特原则

迪米特法则(LoD)也叫最少知识原则,如果两个类不必彼此直接通信,呢

么这两个类就不应当发生直接的相互作用。如果其中一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用[3]。迪米特法则其根本思想是强调了类之间的松耦合。类之间的耦合越弱,越有利于复用,一个处在弱耦合的类被修改,不会对有关系的类造成波及。也就是说,信息的隐藏促进了软件的复用。[6]

例如,在外观模式中,为子系统中的一组接口提供一个一致的界面,此模式

定义了一个高层接口,这个接口使得这一子系统更加容易使用[1]。外观模式完美地体现了迪米特法则的思想。而企业软件中的三层或N层架构,层与层之间地分离其实就是外观模式的体现。

2.2 总体架构 2.2.1层次划分

目前,典型的分层架构是三层架构,即自底向上依次是数据访问层、业务逻

辑层和表示层。

这种经典架构经历了时间的考验和实践的多次检验,被认为是合理、有效的分层设计,所以,在本课题中,将沿袭这种经典架构,使用数据访问层、业务逻辑层和表示层的三层架构体系。 2.2.2 职责划分

在典型的三层架构中,对层次各自的职责划分并没有一个统一的规范,综合

现有的成功实践和.NET平台的特殊性,在本课题中将三层架构的职责划分如下:

数据访问层——负责与数据源的交互,即数据的插入、删除、修改以及从数

据库中读出数据等操作。对数据的正确性和可用性不负责,对数据的用途不了解,不负担任何业务逻辑。

业务逻辑层——负责系统领域业务的处理,负责逻辑性数据的生成、处理及

转换。对流入的逻辑性数据的正确性及有效性负责,对流出的逻辑性数据及用户性数据不负责,对数据的呈现样式不负责。

表示层——负责接收用户的输入、将输出呈现给用户以及访问安全性验证。

对流入的数据的正确性和有效性负责,对呈现样式负责,对呈现友好的错误信息负责。

2.2.3 模块划分及交互设计

综合以上分析,可在宏观上将整个系统分为一下几个模块:

实体类模块——一组实体类的集合,负责整个系统中数据的封装及传递。 数据访问层接口族——一组接口的集合,表示数据访问层的接口。 数据访问层模块——一组类的集合,完成数据访问层的具体功能,实现数据

访问层接口族。

业务逻辑层模块——一组类的集合,完成业务逻辑层的具体功能,实现业务

逻辑层接口族。

表示层模块——程序及可视元素的集合,负责完成表示层的具体功能。 辅助类模块——完成辅助性功能。

各个模块的划分及交互性如图2.1所示:(其中单向箭头表示实泛化,双向

箭头表示依赖及调用)

表示层 业务逻辑层 IDAL 数据访问层 数据源 实体类 辅助类

三、关键性构件及各层次实现

3.1 实体的识别及数据库设计 3.1.1识别实体

根据对网上购物系统的需求分析,可以识别出一下几个实体:

", 用户(Users):代表使用网上购物系统的用户,包括注册会员、管理员。 ", 图书(Books):代表库存的图书。

", 图书分类(Categories):代表库存图书的种类。 ", 图书出版社(Publishers):代表图书出版社。

", 订单(Orders):代表使用网上购物系统的用户的订单。

", 图书订单(OrderBook):代表使用网上购物系统的用户的订单的详细信息。 ", 关键字搜索(SearchKeyword) 逻辑结构设计

附件表(Attachment)(可存入非主要字段) 字段名 附件ID 图书ID 附件或附加信息类型 字段 Id BookId AttaType 类型 长度 int int int 允许空 否 否 否 说明 主键 所在的图书ID 如0(默认)表示图片,1表示编辑推荐内容 3.1.2 数据库设计

附件或附加信息 AttaValue Nvarchar(MAX) 否 附件或附加信息信息 图书表(Books) 字段名 图书ID 字段 Id 类型 长度 int 允许空 否 说明 主键,与Attachment表的BookId构成主外键 Publishers表的外键 图书字数 Image的URL Categories表的外键 0代表否,1代表是 图书标题 作者 出版社ID 出版日期 标准书号 字数 单价 折扣 Title Author PublisherId PublishDate ISBN WordsCount UnitPrice Discount nvarchar(200) nvarchar(200) int datetime nvarchar(50) int money float 否 否 否 否 否 否 否 是 是 是 是 是 是 否 是 是 内容简介 ContentDescription nvarchar(MAX) 作者简介 AuthorDescription nvarchar(MAX) 是否存在编辑推荐 是否存在图片 图书目录 图书分类ID 点击数 是否推荐 图书分类表Categoriges 字段名 分类ID 字段 Id 类型长度 int EditorComment Images TOC CategoryId Clicks IsEditorComment nvarchar(MAX) nvarchar(50) nvarchar(MAX) int int int 允许空 否 说明 主键与Users表的

CategoryId构成主外键 分类名 图书出版社表Publishers 字段名 出版社名ID 字段 Id 类型长度 int 允许空 否 说明 主键 与Users表的PublisherId构成主外键 Name nvarchar(200) 否 出版社名称 用户表Users 字段名 用户ID Name nvarchar(200) 否 字段 Id 类型长度 int 允许空 否 说明 主键 与Orders表的UserId构成主外键 0表示普通会员 1表示管理员 1表示未审批 0表示正常 2表示冻结 登陆账号 登录密码 用户真实姓名 联系地址 联系电话 邮箱 用户角色 LoginId LoginPwd Name Address Phone Mail UserRoleId nvarchar(50) nvarchar(50) nvarchar(50) nvarchar(200) nvarchar(100) nvarchar(100) int 否 否 否 否 否 否 否 用户状态 UserStateId int 否 订单表(Orders)

字段名 订单ID 字段 Id 类型 长度 int 允许空 否 说明 主键 与OrderBook表的OerderId构成主外键 订购日期 用户ID 总额 订单状态 OrderDate UserId datetime int 否 否 否 否 Users表的外键 已发货 已收货已收款 TotalPrice decimal(10,2) OrderState nvarchar(10) 图书订单表(OrderBook) 字段名 图书订单ID 订单ID 图书ID 订购数量 单价

3.2 实体类设计

3.2.1 实体类概述、作用及设计目标

实体类是对实体的封装,是现实世界中实体的计算机表示。它通常包括私有

字段 Id OrderId BookId Quantity UnitPrice 类型 长度 int int int int Decimal(18,0) 允许空 否 否 否 否 否 说明 主键 Orders表的外键 Books表的外键 变量及对应的get、set方法,而在C#语言中,将get、set方法又组合成属性。这些私有变量或者属性,则对应现实实体相应的属性。

实体类的作用主要有两个,一是作为现实实体的计算机代表,二是数据的传

递。在分层架构的应用中,数据正是封装在实体类中,然后以实体类为载体在各个层次间传递。这样不但符合面向对象设计的原则,也便于对数据存取进行控制。

理想情况下,实体类中不能含有任何逻辑,它应该单纯是数据的封装。所以,

它不应该有方法,当然构造函数除外。

基于以上分析,我们设计的实体类,应该是准确、干净、易用。准确表明实

体类应该准确无误地表示现实中的实体,干净表示实体类应该仅包含数据的封装而不掺杂任何逻辑或者与数据封装无关的东西,易用表示实体类应该很容易地用

来在各层之间传递数据。

3.2.2 实体类的设计方案及其比较

一般认为,实体类的设计非常简单,而且系统中仅需要一种实体类即可。但

是,在分层架构中出现了一些新情况,导致了一些变化。

我们知道,实体类负责整个系统数据的传输,从表示层到数据访问层,甚至在JavaScript中,都能看到它的身影,因此可以说,它与各层的耦合度是相当高的,由于实体类的存在,系统各层之间多了一个间接的耦合,我把它叫做实体类耦合。实体类耦合有时是非常危险的。

理想的分层架构,应该是各层可独立替换的。例如,将数据访问层替换掉,

并不应该导致业务逻辑层和表示层的丝毫改动,只要实现了约定接口的数据访问层,都应该可以替换进来。但是,如果某一个新的数据访问层使用的实体类和原实体类不一致,那么当这个数据访问层替换进来后,就需要修改其它所有层次,将其中的实体类进行替换。这严重破坏了开放-关闭原则,也严重影响了分层架构的质量。

这种情况,在现实中是完全可能发生的。例如,我们之前是用的朴素数据访

问层设计,即动态生成SQL语言或调用存储过程的方法,那么,我们的实体类应该是已经设计好的“干净”实体类。而某一天,我们需要改用原有框架设计数据访问层,而假设原有机制用到的实体类是自动生成的,它是不“干净”的,其中添加了很多专为原有机制而设计的代码。这些实体类,与原实体类完全不兼容。

为避免这种情况,就需要对实体类耦合解耦。解耦的方法有两种:一是使用

Adapter模式,二是使用转换器。不过,本文并不会对这两种方法做详细的介绍。 3.2.3 实体类的实现

3.3 接口设计

3.3.1 接口概述及其作用

这里的“接口”一词,特指在分层架构中底层向顶层开放的可调用方法,具本课题约定,实体类命名规则为“表名”。 以用户实体为例,Users的完整代码见附录一。

体到本课题的Demo中,特指数据访问层接口和业务逻辑层接口。

接口在技术上编写难度不大,但是其意义十分重大。总体来说,接口有着一

下几个作用:

", 接口明确了各层次的职责。

", 接口决定了各个层次具体需要实现的功能。 ", 接口形成了整个分层架构的骨架

", 接口暴露了层次的API,为上层提供了依赖点。

因此,接口的设计实际上处在现实需求和程序实现之间,起到承上启下的用。

它决定了需求分析中的各个需求如何合理地映射成各个层次的不同方法。所以接口的设计应该在需求分析的基础上进行。 3.3.2 数据访问层接口的设计

因为接口直接关系到层次的职责,所以,在设计数据访问层接口之前,需要

对数据访问层的职责进行明确。

在本课题中,将数据访问层职责叙述如下:数据访问层负责与数据源的交互,

负责数据的创建、删除、更新及查询工作。它不应该包含任何业务逻辑或可视性元素,对它所处理数据的业务意义是“无知”的。它与数据库系统一起负责数据完整性。

具体来说,数据访问层的接口一般包含以下几种类型的操作:

创建:在数据库中插入新记录,无返回值或返回表示操作状态的标志值。 删除:在数据库中删除符合条件的记录,一般无返回值或返回表示操作状态

的标志值。

更新:将数据库中符合条件的记录更新,一般无返回值或返回表示操作状态

的标志值。

单实体查询:从数据库中读出符合条件单条记录的信息,一般返回单个实体

类。

集合实体查询:从数据库中读出符合条件的多条记录的信息,一般返回实体

类集合。

函数查询:根据一定的函数规则,根据数据记录查询相应的函数值,如查询

某个表的记录数目,返回指定函数值。

以实体用户为例,根据需求分析,数据访问层接口设计如表所示。

需求 获取用户信息 获取全部用户 获取特定状态用户 添加新用户 删除用户 更新用户信息 修改用户密码 修改用户状态 判断是否存在此用户 接口 GetModel GetModelList GetModelList AddUser DeleteUser UpdateUser UpdatePwd 参数 用户名 无 用户状态 返回值 用户实体类 用户实体类 用户实体类 操作类型 单实体查询 集合实体查询 集合实体查询 创建 删除 更新 更新 更新 函数查询 用户实体类 表示是否成功的布尔值 表示是否成功用户ID 的布尔值 用户实体类 表示是否成功的布尔值 用户实体类 表示是否成功的布尔值 UpdateUserState 用户状态ID、表示是否成功的布尔值 用户ID IsExist 用户名

表示是否成功的布尔值 具体IUsersDAL的实现代码请参考附录一

3.3.3 业务逻辑层接口的设计

与数据访问层接口的设计一样,在设计业务逻辑层的接口前,首先应明确其

职责。

本课题将业务逻辑层的职责叙述如下:业务逻辑层负责完成与系统领域相关

的业务逻辑操作,实现过程中的数据访问操作通过调用数据访问层实现。它对业务相关的数据有效性负责,但是不负责UI输入数据的有效性。业务逻辑层中不能含有与显示相关的逻辑,不能决定或影响数据最终的呈现样式。

由于不同领域的业务逻辑差别很大,所以无法像数据访问层那样对接口操作

做出明确的分类。

在实际项目开发中,业务逻辑层接口的设计往往要和领域专家合作。而在本

课题的Demo中,由于网上购物系统的领域业务大家都很熟悉,所以不用进行专门的领域逻辑调研。

下面以用户实体为例,业务逻辑层接口设计如表所示。 需求 获取用户信息 获取全部用户 获取特定状态用户 添加新用户 删除用户 更新用户信息 修改用户密码 修改用户状态 判断是否存在此用户 接口 GetModel GetModelList GetModelList AddUser DeleteUser UpdateUser UpdatePwd 参数 用户名 无 用户状态 返回值 用户实体类 用户实体类 用户实体类 操作类型 单实体查询 集合实体查询 集合实体查询 创建 删除 更新 更新 更新 函数查询 用户实体类 表示是否成功的布尔值 表示是否成功用户ID 的布尔值 用户实体类 表示是否成功的布尔值 用户实体类 表示是否成功的布尔值 UpdateUserState 用户状态ID、表示是否成功的布尔值 用户ID IsExist 用户名

表示是否成功的布尔值 具体UsersBLL的实现代码请参考附录一。

四、三层架构中常用的设计模式

4.1 依赖注入与控制反转

依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一

个概念。具体含义是:当某个角色(调用者)需要另一个角色(被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在具有依赖注入的系统里,创建被调用者的工作不再由调用者来完成,因此称为控制反转。创建被调用者实例的工作通常由Ioc容器来完成,然后注入调用者,因此也称为依赖注入。

具体到分层架构中,依赖注入可以这样理解:当上层类的需要调用下层类功

能时,不再是由上层类直接实例化下层类,而是通过IoC容器获取一个下层类的

实例,然后注入到上层类中。

以用户实体的业务逻辑层调用数据访问层为例,在没有依赖注入机制的系统

中,用户的业务逻辑层类直接实例化数据访问层类,如图4.1(a)所示。在加入依赖注入机制后,实例化数据访问层的任务就交给了IoC容器,如图4.5(b)所示

图4.1(a)非IoC耦合示意

图4.1(b) IoC耦合示意

这样做的好处是什么呢?前面已经提到过,在我们设计的分层架构中层次之

间一定不能出现具体耦合。如果按照图4.1(a)的模式,业务逻辑层势必要实例化具体的数据访问层类,这就造成了紧耦合。而在依赖注入机制下,业务逻辑层可以只依赖数据访问层的接口,至于在运行时得到的是哪种数据访问层类,它并不需要知道,他只需从IoC中获得相应的类,然后调用它的方法完成任务就行了。

而IoC内部可以有一套配置机制,这样就可以根据不同的配置信息,动态决定实例化那一种数据访问层类,从而实现了两个层次间的解耦。由于团队的各方面的因素,本文的在线购物实例采用了图4.1(a)的模式。图4.1(b) 的模式并不展开讨论,想了解这方面知识的读者请查阅相关的资料。 4.2 Abstract Factory模式在三层架构的应用

Abstract Factory模式是在依赖注入机制中广泛采用的设计模式,Spring的IoC

容器就采用了这个经典模式。它的中文译名叫做“抽象工厂”,其定义是这样的:提供一个接口,用于创建相关或依赖对象的家族,而不需要指定具体类。

图4.2抽象工厂模式

图4.2是Abstract Factory模式的示意图。IFactory为工厂接口,它内部定义了生产一系列产品的方法。其它所有工厂都必须实现这个接口,但它们生产的产品系列是不一样的,而一系列产品的每一种产品都实现自同一个产品接口。这样,客户(Client)仅需要依赖工厂接口和产品接口。如果配置文件决定实例化哪一个工厂,则客户就能在运行时动态获得不同的产品系列,从而系统获得了依赖注入的功能。

下面具体到本课题中,讨论抽象工厂在依赖注入机制中的应用。以数据访问

层注入到业务逻辑层为例(业务逻辑层注入到表示层的原理类似),先假设系统

仅有用户一个实体,并且我们的系统需要能访问SQLServer和Access两个数据库,那么,系统中就需呀SqlServerDAL和AccessDAL两个数据访问层,它们都含有一个数据访问类,分别是SqlServerUsersDAL(对应本文实例工程BookStoreDAL中SqlServer文件夹下的Users)和AccessUsersDAL(对应本文实例工程BookStoreDAL中Access文件夹下的Users)。此时,用户的业务逻辑层类UsersBLL(对应本文实例工程BookStoreBLL中的Users)作为客户类,不应该与具体的数据访问层类耦合,而应该先定义接口IUsersDAL(对应本文实例工程BookStoreiDAL中的IUsers)接口,让业务逻辑层与这个接口耦合。再设计SqlServerDALFactory与AccessDALFactory,分别作为生成两种数据访问层的工厂,最后通过配置信息,决定在业务逻辑层中实例化哪个工厂。

图4.3 抽象工厂模式在三层架构中的应用

4.3 三层架构中的外观模式(Facade)

外观模式(Facade)为子系统中的一组接口提供一个一致的界面,此模式定

义了一个高层接口,这个接口使得这一子系统更加容易使用[1]

图4.4 外观模式(Facade)结构图

图4.2是Facade模式的示意图。在设计初期阶段,应该要有意识的讲不同的两个层分离。经典的三层架构,就需要考虑在数据访问层、业务逻辑层和表示层的层与层之间建立外观Facade,这样可以为复杂的子系统提供一个简单的接口,使得耦合大大降低。

致谢

感谢指导老师对我的关心、鼓励与帮助;感谢同学张三、李四和王五的热情支持和真诚帮助;感谢家人在十几年的求学生涯中,给予的教导、爱护与支持,促使我在人生的道路上不断奋力前行。

由于自身知识的不足,文中必存在不少疏漏和不足。敬请老师提出宝贵的意见,并衷心感谢。

[参考文献]

[1]Erich Gamm, Richard Helm, Ralph Johnson, JohnVlissides.设计模式:可复用面向对象软件的基础[M].北京:机械工业出版社,2007.

[2]Robert C.Martin.敏捷软件开发:原则、模式与实践[M].北京:清华大学出版社,2003. [3]阎宏.Java与模式[M].北京:电子工业出版社,2002.

using System.Collections.Generic; using System.Text; using BookStoreDALFactory; using BookStoreIDAL;

namespace BookStoreBLL {

public class Users {

private static AbstractDALFactory _BookStoreFactory = AbstractDALFactory.DALFactory(); private static IUsers _User=_BookStoreFactory.CreateUsers();//直接得到实际的数据库访问实例

public static BookStoreModels.Users GetModel(string loginId,int userRole) {

return _User.GetModel(loginId,userRole); }

public static BookStoreModels.Users GetModel(int _UserId) {

return _User.GetModel(_UserId); }

public static List GetModelList() {

return _User.GetModelList(); }

public static List GetModelList(int userState) {

return _User.GetModelList(userState); }

///

/// 添加用户 ///

///

/// 添加成功放回true 添加失败返回false public static bool AddUser(BookStoreModels.Users _UserModel) {

return _User.AddUser(_UserModel); }

///

/// 删除用户

///

///

/// 添加成功放回true 添加失败返回false public static bool DeleteUser(int Id) {

return _User.DeleteUser(Id); }

///

/// 修改用户状态 ///

///

/// 修改成功放回true 修改失败返回false public static bool UpdateUserState(int _UserStateId, int _Id) {

return _User.UpdateUserState(_UserStateId,_Id); }

///

/// 判断是否存在此类型用户

/// 如果_UserRoleId=3则代表要早所有用户 ///

/// ///

public static bool IsExistSpecialUser(int _UserStateId) {

return _User.IsExistSpecialUser(_UserStateId); }

///

/// 判断是否存在此用户(系统中会员用户名是唯一的) ///

/// ///

public static bool IsExist(string _LoginId) {

return _User.IsExist(_LoginId); }

///

/// 更新用户信息 ///

///

/// 修改成功放回true 修改失败返回false public static bool UpdateUser(BookStoreModels.Users _UserModel)

{

return _User.UpdateUser(_UserModel); }

///

/// 修改用户密码 ///

///

/// 修改成功放回true 修改失败返回false public static bool UpdatePwd(BookStoreModels.Users _UserPw) {

return _User.UpdatePwd(_UserPw); } } }

抽象工厂类:BookSoreDALFactory.AbstractDALFactory.cs

using System;

using System.Collections.Generic; using System.Text; using BookStoreIDAL; using System.Configuration;

namespace BookStoreDALFactory {

public abstract class AbstractDALFactory {

public static AbstractDALFactory DALFactory() {

string dbType = ConfigurationManager.AppSettings[\].ToString(); AbstractDALFactory _DALFactory = null; switch(dbType) {

case \:

_DALFactory = new SqlServerFactory(); break; case \:

_DALFactory = new AccessFactory(); break; //... }

return _DALFactory;

}

//数据访问对象创建接口(抽象工厂提供抽象产品)解除具体数据访问的耦合 public abstract IAttachment CreateAttachment(); public abstract IBooks CreateBooks();

public abstract ICategories CreateCategories(); public abstract IOrderBook CreateOrderBook(); public abstract IOrders CreateOrders();

public abstract IPublishers CreatePublishers(); public abstract ISearchKeyword CreateSearchKeyword(); public abstract IUsers CreateUsers(); } }

本文来源:https://www.bwwdw.com/article/ygp7.html

Top