以前没太多关注各多层架构的设计,一直以来都是用的三层架构做网站,最近对N层架构有些兴趣,就稍微研究了一下,由于自己也没怎么用过,也是才学习,中间可能有些错误,请大家指正。
ASP.NET的框架不管有多少层架构,都脱离不了最基本的三层:表现层,业务层,数据访问层。
整个过程的来回都跟请求和数据有关,往右发送请求,往左响应请求返回数据。
最简单的三层结构:Default.aspx——>BLL——>SQLHelper
Default.aspx<——BLL<——SQLHelper
多层架构既然是基于三层架构的,它是对最基础的三层结构进行再抽离,那么就可以在三层架构的基础上再至少抽出一个中间层,是最原始的三层架构之间的桥梁,它起到一个衔接作用。试想一个业务比较复杂的网站,BLL的代码量会比较庞大,基本的三层显然是不够用的。我的做法是在三层的基础之上,先给Web和BLL之间搭一座桥,我叫它BLLManager,它的作用就是来统一管理所有的BLL类;这还不够,我把和SQLHelper相关的数据访问类都放到DAL中(以前的做法是用BLL来访问SQLHelper),这就相当于业务的数据都在DAL中请求和获得;然后我再在BLL和DAL中抽出一个类DALFactory用来管理所有的DAL(除了SQLHelper)。现在基本的结构如下图(不知道我的理解对不对,希望大家指正):
使用N层架构的效果:每一层都可以在仅仅更改很少量的代码后,就能放到物理上不同的服务器上使用,因此结构灵活而且性能更佳。此外,每层做些什么其它层是完全看不到的,因此更改、更新某层,都不再需要重新编译或者更改全部的层了。这是个很强大的功能。例如,如果把数据访问代码与业务逻辑层分离,当数据库服务器更改后,你只需要更改数据访问的代码,因为业务逻辑层是不变的,因此不需要更改或者重新编译业务逻辑层。
下面我给了个简单的例子:
Default.aspx
Code
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Test._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="查询" onclick="Button1_Click" />
<div id="infoList" runat="server">
</div>
</form>
</body>
</html>
Default.aspx.cs
Code
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using Model;
using Test.Common;
namespace Test
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
string name = this.TextBox1.Text;
StringBuilder info = new StringBuilder();
info.Append("<table border='1'>");
info.Append("<tr>");
info.Append("<td>编号</td>");
info.Append("<td>姓名</td>");
info.Append("<td>入职时间</td>");
info.Append("</tr>");
IList<Emp> empList = BLLManager.Instance.EmpBLL.GetEmpList(name);
if (empList!=null)
{
foreach (Emp emp in empList)
{
info.Append("<tr>");
info.Append("<td>"+emp.EmpId+"</td>");
info.Append("<td>"+emp.EmpName+"</td>");
info.Append("<td>" + String.Format("{0:yyyy-MM-dd}", emp.HireDate) + "</td>");
info.Append("</tr>");
}
}
info.Append("</table>");
this.infoList.InnerHtml = info.ToString();
}
}
}
Emp.cs
Code
using System;
using System.Collections.Generic;
using System.Text;
namespace Model
{
public class Emp
{
private int empId;
private string empName;
private DateTime hireDate;
public int EmpId
{
get { return empId; }
set { empId = value; }
}
public string EmpName
{
get { return empName; }
set { empName = value; }
}
public DateTime HireDate
{
get { return hireDate; }
set { hireDate = value; }
}
}
}
BLLManager.cs
Code
using System;
using System.Collections.Generic;
using System.Web;
using BLL;
namespace Test.Common
{
/**//// <summary>
/// BLLManager类,统一管理所有的BLL,作为Web层和BLL层的中间层,用来返回BLL类库中某个类的实例
/// 这个类采用单例模式,确保系统中只有一个BLLManager类
/// </summary>
public class BLLManager
{
private static BLLManager _instance;
private BLLManager()
{
}
public static BLLManager Instance
{
get
{
if (_instance == null)
{
lock (typeof(BLLManager))
{
if (_instance == null)
{
_instance = new BLLManager();
}
}
}
return _instance;
}
}
public EmpBLL EmpBLL
{
get { return new EmpBLL(); }
}
}
}
EmpBLL.cs
Code
using System;
using System.Collections.Generic;
using System.Text;
using DAL;
using Model;
namespace BLL
{
/**//// <summary>
///
/// </summary>
public class EmpBLL
{
public EmpBLL()
{
DAL = DALFactory.CreateEmpDAL();
}
/**//// <summary>
/// DAL作为EmpBLL的属性,用来get,set对应的EmpDAL类的实例
/// </summary>
public EmpDAL DAL { get; set; }
public IList<Emp> GetEmpList(string name)
{
return DAL.GetEmpListByName(name);
}
}
}
DALFactory.cs
Code
using System;
using System.Collections.Generic;
using System.Text;
using Model;
using DAL;
namespace BLL
{
/**//// <summary>
/// DALFactory用来管理所有的DAL类,实例化DAL,所有的DAL类都在这里被实例化
/// </summary>
public class DALFactory
{
public static EmpDAL CreateEmpDAL()
{
return new EmpDAL();
}
}
}
EmpDAL.cs
Code
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using Model;
namespace DAL
{
/**//// <summary>
/// 这一层是数据访问层,和实体类打交道,最终返回的也是一些对象
/// 我的理解是SQLHelper是数据库访问层,是和数据库直接相关的,这应该是两个不同的层次
/// </summary>
public class EmpDAL
{
public IList<Emp> GetEmpListByName(string name)
{
List<Emp> items = null;
SqlParameter[] parms = new SqlParameter[]{
new SqlParameter("@Name",SqlDbType.VarChar,20)
};
parms[0].Value = name;
//调用存储过程
using (SqlDataReader reader = SQLHelper.ExecuteReader(SQLHelper.CONN_STRING, CommandType.StoredProcedure, "EmpsGetByName", parms))
{
while(reader.Read())
{
//isDBNull()
// 在c#中,进行数据库查询时使用IsDbNull 方法判断数据库中字段值是否存在(注意不是判断是否空值或0) //。将字段所在的行key作为参数传给IsDbNull 方法,此方法对其值进行判断,如果字段值不存在或缺少值则返 //回Ture,如果字段值存在则返回False。
//此方法能方便地对数据库中值的存在与否和是否缺失进行判断,避免了空值的干扰。
int empid = !reader.IsDBNull(0)?reader.GetInt32(0):0;
string empname = !reader.IsDBNull(1)?reader.GetString(1):string.Empty;
DateTime hiredate = !reader.IsDBNull(2)?reader.GetDateTime(2):DateTime.Today;
Emp emp = new Emp();
emp.EmpId = empid;
emp.EmpName = empname;
emp.HireDate = hiredate;
if(items==null)
{
items = new List<Emp>();
}
items.Add(emp);
}
}
return items;
}
}
}
SQLHelper.cs我就不贴了。下面有整个源码(包含sql)的下载
/Files/psunny/N-tier-structure.rar
注:本文转自http://www.cnblogs.com/psunny/archive/2009/08/16/1547724.html