這幾天看了不少三層架構的資料,整理整理
——故寫篇博文談談自己的看法。
三層架構概念:
三層架構(3-tier application) 通常意義上的三層架構就是將整個業務應用划分為:表現層(UI)、業務邏輯層(BLL)、數據訪問層(DAL)。區分層次的目的即為了“高內聚,低耦合”的思想,復雜項目不能把SQL語句直接寫到程序里,不模塊話,難以維護。應該采取三層架構。
1、表現層(UI):通俗講就是展現給用戶的界面,即用戶在使用一個系統的時候他的所見所得。
2、業務邏輯層(BLL):針對具體問題的操作,也可以說是對數據層的操作,對數據業務邏輯處理。
3、數據訪問層(DAL):該層所做事務直接操作數據庫,針對數據的增添、刪除、修改、查找等。
簡單的說,UI層調用BLL,BLL調用DAL,數據用Model進行傳遞,Model為各層之間架起了數據傳輸的橋梁。
參考模型:UI<-->Model<-->BLL<-->Model<-->DAL
傳統的兩層結構和三層架構之間的區別:
下面我以一個簡單的例子來細數三層架構:
代碼剖析:
- 新建一個項目(Windows 窗體應用程序),再在根目錄下新建3個文件夾,分別是Model,DAL,BLL。
- 在Model下添加一個Person類
- 在DAL下添加一個SQLHelper類和一個PersonDAL類。
- 在BLL下添加PersonBLL類
Person.cs代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 三層架構Demo.Model
{
class Person
{
public int Id { get;set;}
public int Age { get; set; }
public string Name { get; set; }
}
}
SQLHelper類,封裝了數據庫操作的方法:
SQLHelper.cs代碼入下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Configuration;
using System.Data;
namespace 三層架構Demo.DAL
{
class SQLHelper
{
//public static readonly string connStr = System.Configuration.ConfigurationSettings.AppSettings["dbconnstr"];
//獲得連接字符串
public static readonly string connStr =
ConfigurationManager.ConnectionStrings["dbconnstr"].ConnectionString;
/// <summary>
/// 執行方法ExecuteNonQuery
/// </summary>
/// <param name="cmdText">要執行的sql語句</param>
/// <param name="parameters">參數數組</param>
/// <returns>受影響的行數</returns>
public static int ExecuteNonQuery(string cmdText,
params SqlParameter[] parameters)
{
using (SqlConnection conn=new SqlConnection (connStr))
{
conn.Open();
using (SqlCommand cmd= conn.CreateCommand())
{
cmd.CommandText = cmdText;
cmd.Parameters.AddRange(parameters);
int i=cmd.ExecuteNonQuery();
return i;
}
}
}
/// <summary>
/// 執行ExecuteScalar() 返回第一行第一列數據
/// </summary>
/// <param name="cmdText">要執行的sql語句</param>
/// <param name="parameters">參數數組</param>
/// <returns>返回第一行第一列數據</returns>
public static object ExecuteScalar(string cmdText,
params SqlParameter[] parameters)
{
using (SqlConnection conn=new SqlConnection(connStr))
{
conn.Open();
using (SqlCommand cmd=conn.CreateCommand())
{
cmd.CommandText = cmdText;
cmd.Parameters.AddRange(parameters);
return cmd.ExecuteScalar();
}
}
}
/// <summary>
/// 執行ExecuteDataTable()方法
/// </summary>
/// <param name="cmdText">要執行的Sql語句</param>
/// <param name="parameters">參數數組</param>
/// <returns>返回一個DataTable</returns>
public static DataTable ExecuteDataTable(string cmdText,
params SqlParameter[] parameters)
{
using (SqlConnection conn=new SqlConnection (connStr))
{
conn.Open();
using (SqlCommand cmd=conn.CreateCommand())
{
cmd.CommandText = cmdText;
cmd.Parameters.AddRange(parameters);
using ( SqlDataAdapter adapter=new SqlDataAdapter (cmd))
{
DataTable dt = new DataTable();
adapter.Fill(dt);
return dt;
}
}
}
}
/// <summary>
/// 執行ExecuteSqlDataReader()方法
/// </summary>
/// <param name="cmdText">要執行的Sql語句</param>
/// <param name="parameters">參數數組</param>
/// <returns>返回一個SqlDataReader</returns>
public static SqlDataReader ExecuteSqlDataReader(string cmdText,
params SqlParameter[] parameters)
{
using (SqlConnection conn=new SqlConnection (connStr))
{
conn.Open();
using (SqlCommand cmd=conn.CreateCommand())
{
cmd.CommandText = cmdText;
cmd.Parameters.AddRange(parameters);
return cmd.ExecuteReader();
}
}
}
}
}
PersonDAL.cs代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using 三層架構Demo.Model;
using System.Data.SqlClient;
using System.Data;
namespace 三層架構Demo.DAL
{
class PersonDAL
{
/// <summary>
/// 返回一個新增對象的主鍵,設為自動增長
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public int Addnew(Person model)
{
string sql = "insert into T_person(Age,Name) output inserted.id values(@Age,@Name)";
object obj=
SQLHelper.ExecuteScalar(sql,new SqlParameter("Age",model.Age),new SqlParameter("Name",model.Name));
//Convert : 與 value 等效的 32 位有符號整數,如果 value 為 null,則為零。
return Convert.ToInt32(obj);
}
/// <summary>
/// 刪除數據
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public int Delete(int id)
{
string sql = "delete form T_Person where Id=@Id";
return SQLHelper.ExecuteNonQuery(sql,new SqlParameter("Id",id));
}
/// <summary>
/// 修改數據
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public int Update(Person model)
{
string sql = "update T_Person set Age=@Age,Name=@Name where Id=@Id";
return SQLHelper.ExecuteNonQuery(sql,new SqlParameter("Age",model.Age),new SqlParameter("Name",model.Name),
new SqlParameter("Id",model.Id));
}
/// <summary>
/// 查詢數據
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public Person Get(int id)
{
string sql="select * from T_Person where Id=@Id";
DataTable dt=SQLHelper.ExecuteDataTable(sql,new SqlParameter("Id",id));
if (dt.Rows.Count<=0)
{
return null;
}
else if (dt.Rows.Count==1)
{
Person model1 = new Person();
model1.Id = Convert.ToInt32(dt.Rows[0]["Id"]);
model1.Name = Convert.ToString(dt.Rows[0]["Name"]);
model1.Age = Convert.ToInt32(dt.Rows[0]["Age"]);
return model1;
}
else//以防意外情況
{
throw new Exception("數據庫中有兩條及以上重復數據");
}
}
/// <summary>
/// 獲取全部數據
/// </summary>
/// <returns></returns>
public IEnumerable<Person> GetAll()
{
string sql = "select * from T_Person";
DataTable dt = SQLHelper.ExecuteDataTable(sql);
List<Person> list = new List<Person>();
foreach (DataRow row in dt.Rows)
{
Person model = new Person();
model.Id = Convert.ToInt32(row["Id"]);
model.Name =Convert.ToString(row["Name"]);
model.Age = Convert.ToInt32(row["Age"]);
list.Add(model);
}
return list;
}
}
}
進行邏輯判斷的BLL層代碼看似是這樣的:
PersonBLL.cs代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using 三層架構Demo.Model;
using 三層架構Demo.DAL;
using System.Data.SqlClient;
using System.Data;
namespace 三層架構Demo.BLL
{
class PersonBLL
{
public int Addnew(Person model)
{
return new PersonDAL().Addnew(model);
}
public int Delete(int id)
{
return new PersonDAL().Delete(id);
}
public int Update(Person model)
{
return new PersonDAL().Update(model);
}
public Person Get(int id)
{
return new PersonDAL().Get(id);
}
public IEnumerable<Person> GetAll()
{
return new PersonDAL().GetAll();
}
}
}
UI層進行測試:
Form1.cs代碼如下:
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 三層架構Demo.Model;
using 三層架構Demo.DAL;
using 三層架構Demo.BLL;
namespace 三層架構Demo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Person p1 = new Person();
//p1.Age = 22;
//p1.Name = "Eyes";
//int id=new PersonDAL().Addnew(p1);
//MessageBox.Show(id.ToString());
//PersonDAL p = new PersonDAL();
//Person a = p.Get(1);
//a.Name = "jack";
//MessageBox.Show(a.Name + "," + a.Age);
//p.Update(a);
//PersonBLL bll = new PersonBLL();
//Person p = bll.Get(1);
//p.Name = "Admin";
//MessageBox.Show(p.Name + "," + p.Age);
//bll.Update(p);
PersonBLL b = new PersonBLL();
List<Person> list = (List<Person>)b.GetAll();
foreach (Person item in list)
{
MessageBox.Show(item.Id+","+item.Name+","+item.Age);
}
}
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = new PersonBLL().GetAll();
}
}
}
總結:
優點
1、開發人員可以只關注整個結構中的其中某一層;
2、可以很容易的用新的實現來替換原有層次的實現;
3、可以降低層與層之間的依賴;
4、有利於標准化;
5、利於各層邏輯的復用。
缺點
1、降低了系統的性能。這是不言而喻的。如果不采用分層式結構,很多業務可以直接造訪數據庫,以此獲取相應的數據,如今卻必須通過中間層來完成。
2、有時會導致級聯的修改。這種修改尤其體現在自上而下的方向。如果在表示層中需要增加一個功能,為保證其設計符合分層式結構,可能需要在相應的業務邏輯層和數據訪問層中都增加相應的代碼。
3、增加了開發成本。