三层之代码说话!
昨天和今天一直在看大家发的有关于架构的问题,看多了最后反而到把自己给弄迷糊了。复杂的架构我也不会,评论任何,或许等到哪一天我由一个菜鸟变成一个高手以后,嘿嘿,偶也会去弄一些高深的文章。
关于3层,如果你和我一样是一个刚起步不久的,而且对开发架构有一定兴趣的人,那么以下我写的内容或许对大家认识三层有个形象的了解。
使用n层架构,需要把应用程序的逻辑封装到独立的层中去。大多数情况下,一个Application被推荐分为3层,即:用户界面层、业务逻辑层、数据访问层。
下面,我用一个从书上学来的经典3层例子给大家详细分析一下3层,同时自己也巩固一下。
(该图是数据库中的表和字段,以下操作均围绕该表进行)
首先,我们从数据访问层开始说起,数据访问层封装包含操作数据库的所有代码。以下代码均封装在SamlpeDAL类库下。
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
public class Product
{
private int _id;
public int ID
{
get { return _id; }
set { _id = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private decimal _price;
public decimal Price
{
get { return _price; }
set { _price = value; }
}
private string _description;
public string Description
{
get { return _description; }
set { _description = value; }
}
public Product(int id,string name,decimal price,string description)
{
_id = id;
_name = name;
_price = price;
_description = description;
}
public Product(string name, decimal price, string description)
: this(0, name, price, description)
{ }
}
(如果你对抽象工厂开发模式也有研究的话,其实实体类应该放在Model层下的)
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
public class SqlDataAccess
{
private static readonly string _connString = string.Empty;
static SqlDataAccess()
{
_connString = "server=.\\mssql2005;database=dbProduct;user=sa;pwd=welcome";
}
public List<Product> ProductSelectAll()
{
List<Product> products = new List<Product>();
SqlConnection objConn = new SqlConnection(_connString);
SqlCommand objComm = new SqlCommand();
objComm.Connection = objConn;
objComm.CommandText = "select * from products";
using (objConn)
{
objConn.Open();
SqlDataReader objReader = objComm.ExecuteReader();
while (objReader.Read())
{
products.Add(new Product(
(int)objReader["Id"],
(string)objReader["Name"],
(decimal)objReader["Price"],
(string)objReader["Description"]));
}
return products;
}
}
public void ProductInsert(Product newProduct)
{
SqlConnection objConn = new SqlConnection(_connString);
SqlCommand objComm = new SqlCommand();
objComm.Connection = objConn;
objComm.CommandText = "insert Products(Name,Price,Description) values(@Name,@Price,@Description)";
objComm.Parameters.AddWithValue("@Name", newProduct.Name);
objComm.Parameters.AddWithValue("@Price", newProduct.Price);
objComm.Parameters.AddWithValue("@Description",newProduct.Description);
using (objConn)
{
objConn.Open();
objComm.ExecuteNonQuery();
}
}
public void ProductUpdate(Product productToUpdate)
{
SqlConnection objConn = new SqlConnection(_connString);
SqlCommand objComm = new SqlCommand();
objComm.Connection = objConn;
objComm.CommandText = "update Products set Name=@Name,"
+"Price=@Price,Description=@Description where Id=@Id";
objComm.Parameters.AddWithValue("@Name", productToUpdate.Name);
objComm.Parameters.AddWithValue("@Price",productToUpdate.Price);
objComm.Parameters.AddWithValue("@Description",productToUpdate.Description);
objComm.Parameters.AddWithValue("@Id",productToUpdate.ID);
using (objConn)
{
objConn.Open();
objComm.ExecuteNonQuery();
}
}
public void ProductDelete(int id)
{
SqlConnection objConn = new SqlConnection(_connString);
SqlCommand objComm = new SqlCommand();
objComm.Connection = objConn;
objComm.CommandText = "delete Products where Id=@Id";
objComm.Parameters.AddWithValue("@Id", id);
using (objConn)
{
objConn.Open();
objComm.ExecuteNonQuery();
}
}
}
接下来再给大家介绍一下业务逻辑层。业务逻辑层包含所有的商务规则和验证代码,并管理所有界面的数据访问。以下的代码封装在SampleBLL类库中。
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
using SampleDAL;//记住这里要添加对数据访问层的引用
public class BusinessLogic
{
public static List<Product> SelectAll()
{
SqlDataAccess objSqlDataAccess = new SqlDataAccess();
return objSqlDataAccess.ProductSelectAll();
}
public static void Update(int id, string name, decimal price, string description)
{
Product objProduct = new Product(id, name, price, description);
SqlDataAccess objSqlDataAccess = new SqlDataAccess();
objSqlDataAccess.ProductUpdate(objProduct);
}
public static void Insert(string name, decimal price, string description)
{
Product objProduct = new Product(name, price, description);
SqlDataAccess objSqlDataAccess = new SqlDataAccess();
objSqlDataAccess.ProductInsert(objProduct);
}
public static void Delete(int id)
{
SqlDataAccess objSqlDataAccess = new SqlDataAccess();
objSqlDataAccess.ProductDelete(id);
}
}
最后,我们来介绍用户界面层。用户界面层除了界面元素外,不应该包含任何其他内容。用户界面层也不应该包含任何业务逻辑和数据访问。这个例子的用户界面层封装在名为SampleUI的Web Application库中。其效果如图:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" DataSourceID="ObjectDataSource1" DataKeyNames="ID">
<Columns>
<asp:BoundField DataField="ID" HeaderText="ID" SortExpression="ID" ReadOnly="True" />
<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
<asp:BoundField DataField="Price" HeaderText="Price" SortExpression="Price" />
<asp:BoundField DataField="Description" HeaderText="Description" SortExpression="Description" />
<asp:CommandField CancelText="Cancel" DeleteText="Delete" EditText="Edit" ShowEditButton="True"
UpdateText="Update" />
<asp:CommandField DeleteText="Delete" ShowDeleteButton="True" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" DeleteMethod="Delete"
InsertMethod="Insert" SelectMethod="SelectAll" TypeName="SampleBLL.BusinessLogic"
UpdateMethod="Update">
<DeleteParameters>
<asp:Parameter Name="id" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="id" Type="Int32" />
<asp:Parameter Name="name" Type="String" />
<asp:Parameter Name="price" Type="Decimal" />
<asp:Parameter Name="description" Type="String" />
</UpdateParameters>
<InsertParameters>
<asp:Parameter Name="name" Type="String" />
<asp:Parameter Name="price" Type="Decimal" />
<asp:Parameter Name="description" Type="String" />
</InsertParameters>
</asp:ObjectDataSource>
<br />
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
DataSourceID="ObjectDataSource1" DefaultMode="Insert" Height="50px" Width="125px">
<Fields>
<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
<asp:BoundField DataField="Price" HeaderText="Price" SortExpression="Price" />
<asp:BoundField DataField="Description" HeaderText="Description" SortExpression="Description" />
<asp:CommandField ShowInsertButton="True" />
</Fields>
</asp:DetailsView>
</div>
</form>
</body>
从以上所有代码中我们不难看出3层是怎样分开封装,以及3个层之间的是怎样关联工作的。这里值得注意的是,如果你用的是VS,那么这三个层被放在同一个解决方案中是毫无疑问的,只是在一个层中使用另一个层的文件时,记得在引用中添加另一个层即可。