3层架构 - 需要一个例子

Posted

技术标签:

【中文标题】3层架构 - 需要一个例子【英文标题】:3 Tier Architecture - In need of an example 【发布时间】:2011-01-01 23:21:08 【问题描述】:

目前我正在使用单层架构。现在我想学习如何使用 3 层架构编写代码。请你给我一个简单的例子吗?

【问题讨论】:

你可以在其他问题***.com/questions/7510396/…看到我的回答 youtube.com/watch?v=4n3xzK1Cfh0 【参考方案1】:

您所说的“层”是指软件堆栈中的“层”吗? “层”这个词更适合用来描述系统的物理组件。如果你使用的是 ASP.NET,你可能已经有了一个“3 tiered”系统——

    浏览器显示网页 IIS 服务器托管您的应用程序 带有您的数据库的数据库服务器

但您可能会将所有代码放入单个软件“层”——具体来说,就是您的 aspx 页面的代码隐藏文件。您想从单层方法转变为 3 层方法。经典的“3 层”软件架构由以下部分组成——

    表示层

    业务逻辑层 (BLL)

    数据访问层 (DAL)

(来源:asp.net)

对于典型的 ASP.NET 应用程序,您可以按如下方式应用它。首先,创建一个 LINQ2SQL 文件 (.dbml),其中包含用于数据库访问的对象。这是您的数据访问层 (DAL)。

接下来,您可能会创建一个 DLL 来包含您的 业务逻辑层 (BLL)。该层将通过 DAL 访问数据库,根据需要对其进行操作,然后通过简单的接口将其公开。例如,如果您的应用程序显示一个客户列表,您的 BLL 可能有一个名为 GetClientList() 的公共函数,它返回一个客户列表。

最后,您将设置代码隐藏文件以实例化 BLL 并将其连接到接口组件。这是您的表示层。例如,它可能会获取从 GetClientList() 函数返回的数据并将其绑定到 Web 表单上的数据网格。这个想法是让表示层尽可能薄。

这似乎有点冗长,但一旦你完成了几次,它就会非常简单。你会发现像这样分离你的应用程序会让它更容易维护,因为关注点分离会导致代码更简洁。您还会发现升级甚至替换表示层要容易得多,因为它包含的智能很少。最后,您将拥有许多非常有用的 BLL 库,您可以在新应用程序中轻松使用这些库,从而大大提高生产力。

【讨论】:

【参考方案2】:
connection class
-----------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web .UI.WebControls ;
/// <summary>
/// Summary description for conn
/// </summary>
namespace apm_conn

    public class conn
    
        public SqlConnection getcon()
        
            SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["connect"].ConnectionString );
            if (con.State == ConnectionState.Closed)
            
                con.Open();
            
            return con;
        
        #region execute command
        public string  Executecommand(SqlParameter []sqlparm,string sp)
        
            string r_val = "";
            try
            

                SqlConnection con = new SqlConnection();
                con = getcon();
                SqlCommand cmd = new SqlCommand();
                cmd.Connection = con;
                cmd.CommandText = sp;
                cmd.CommandType = CommandType.StoredProcedure;
                foreach (SqlParameter loopvar_parm in sqlparm)
                
                    cmd.Parameters.Add(loopvar_parm);

                
                cmd.Parameters.Add("@Var_Output", SqlDbType.VarChar, 20).Direction = ParameterDirection.Output;
                cmd.ExecuteNonQuery();
                r_val = (string)cmd.Parameters["@Var_Output"].Value;
                con.Close();
            
            catch  
            return r_val;

        

        #endregion
        #region Execute Dataset
         public DataSet ExeccuteDataset(SqlParameter[] sqlParm, string sp)
    
        DataSet ds = new DataSet();
        try
        
            SqlConnection con = new SqlConnection();
            con = getConn();
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = con;
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = sp;
            foreach (SqlParameter LoopVar_param in sqlParm)
            
                cmd.Parameters.Add(LoopVar_param);
            
            cmd.ExecuteNonQuery();
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            da.Fill(ds);

        
        catch
         
        return ds;
    
        #endregion
        #region grid
        public void Bindgrid(DataSet ds,GridView g)
        
            try
            
                g.DataSource = ds.Tables[0];
                g.DataBind();

            
            catch  
        
        #endregion
        #region Dropdownlist
        public void Binddropdown(DropDownList dl,DataSet ds,string text,string value)
        
            try
            
                dl.DataSource = ds.Tables[0];
                dl.DataTextField = text;
                dl.DataValueField = value;
                dl.DataBind();
            
            catch
            

        
        #endregion
        public conn()
        
            //
            // TODO: Add constructor logic here
            //
        
    





dal
---------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using apm_conn;
using System.Data.SqlClient;
using apm_ent;

/// <summary>
/// Summary description for Class1
/// </summary>
namespace apm_dal

    public class dal
    
        conn ob_conn = new conn();
        public dal()
        
            //
            // TODO: Add constructor logic here
            //
        
        public string insert(ent obj_ent)
        
            SqlParameter[] sqlparm =
        
            new SqlParameter ("@Var_Action",obj_ent.Var_Action),
            new SqlParameter ("@Int_Id",obj_ent.Int_Id ),
             new SqlParameter ("@Var_Product",obj_ent.Var_Product ),
              new SqlParameter ("@Dc_Price",obj_ent.Var_Price ),
              new SqlParameter ("@Int_Stat",obj_ent.Int_Stat ),

                               ;
            return ob_conn.Executecommand(sqlparm, "Proc_product");
        
        public string ins(ent obj_ent)
        
            SqlParameter[] parm =
        
            new SqlParameter ("@Var_Action",obj_ent .Var_Action),
            new SqlParameter ("@Int_Id",obj_ent .Int_Id),
                            ;
            return ob_conn.Executecommand(parm, "Proc_product");
        
    



bal
-------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using apm_ent;
using apm_dal;

/// <summary>
/// Summary description for bal
/// </summary>
namespace apm_Bal


    public class bal
    
        dal ob_dal = new dal();
        string r_val = "";
        public bal()
        
            //
            // TODO: Add constructor logic here
            //
        
        public string insert(ent obj_ent)
        
            return ob_dal.insert(obj_ent);
        
    




Ent
------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for ent
/// </summary>
namespace apm_ent

    public class ent
    
        public ent()
        
            //
            // TODO: Add constructor logic here
            //
        
        #region Ent
        public int Int_Id  get; set; 
        public string  Var_Action  get; set; 
        public string Var_Product  get; set; 
        public decimal  Var_Price  get; set; 
        public int Int_Stat  get; set; 
        #endregion
    




page code
--------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using apm_conn;
using apm_ent;
using apm_Bal;
using apm_conn;
public partial class _Default : System.Web.UI.Page

    conn obj_conn = new conn();
    ent obj_ent = new ent();
    bal obj_bal = new bal();
    string r_val = "";
    protected void Page_Load(object sender, EventArgs e)
    

    
    protected void btnsub_Click(object sender, EventArgs e)
    
        obj_ent.Var_Action = "INS";
        obj_ent.Var_Product = txtproduct.Text;
        obj_ent.Var_Price = Convert.ToDecimal (txtprice.Text);
        r_val = obj_bal.insert(obj_ent);
        if (r_val == "1")
        
            Response.Write("<script>alert('Inserted Sucessfully')</script>");
        
    

【讨论】:

【参考方案3】:

三层(层)是一种客户端-服务器架构,其中用户界面、业务流程(业务规则)以及数据存储和数据访问作为独立模块开发和维护,或者通常在单独的平台上进行。

基本上有3层:

第 1 层(表示层、GUI 层) 第 2 层(业务对象、业务逻辑层) 第 3 层(数据访问层)。这些层可以单独开发和测试。

将代码分成 3 层需要什么?将用户界面与业务逻辑和数据库访问分开有很多优点。部分优势如下:

业务逻辑组件的可重用性导致快速 发展。假设我们有一个模块来处理添加、更新、 在系统中删除和查找客户。由于该组件是 开发和测试,我们可以在任何其他项目中使用它 涉及维护客户。

系统的转换很容易。由于业务逻辑是 与数据访问层分离,改变数据访问层 不会对业务逻辑模块产生太大影响。假设我们是 从 SQL Server 数据存储迁移到 Oracle 不应该有任何 业务层组件和 GUI 中所需的更改 组件。

系统的变更管理很容易。假设有未成年人 业务逻辑的变化,我们不必安装整个 个人用户 PC 中的系统。例如。如果 GST (TAX) 从 10% 更改 到 15% 我们只需要更新业务逻辑组件 影响用户并且没有任何停机时间。

拥有独立的功能服务器允许并行开发 由应用专家划分的各个层级。

提供更灵活的资源分配。可以减少网络 通过让功能服务器将数据剥离到精确的流量 发送给客户之前需要的结构。

【讨论】:

【参考方案4】:

这就是我在我的项目中所拥有的。不仅仅是传统的 3 层架构。

1.) Application.Infrastructure

所有业务对象的基类、业务对象集合、数据访问类以及我的自定义属性和实用程序作为扩展方法,通用验证框架。这决定了我最终的 .net 应用程序的整体行为组织。

2.) Application.DataModel

数据库的类型化数据集。 TableAdapters 已扩展以包含我可能需要的事务和其他功能。

3.) Application.DataAccess

数据访问类。 使用底层类型化数据集查询数据库操作的实际位置。

4.) Application.DomainObjects

业务对象和业务对象集合。 枚举。

5.) Application.BusinessLayer

提供可从表示层访问的管理器类。 HttpHandlers。 我自己的 Page 基类。 这里有更多内容..

6.) Application.WebClientApplication.WindowsClient

我的表示层 从 Application.BusinessLayer 和 Application.BusinessObjects 获取引用。

Application.BusinessObjects 在整个应用程序中使用,并在需要时跨越所有层 [Application.DataModel 和 Application.Infrastructure 除外]

我所有的查询都只定义了 Application.DataModel。

Application.DataAccess 作为任何数据访问操作的一部分返回或获取业务对象。业务对象是在反射属性的帮助下创建的。每个业务对象都标有到数据库中目标表的属性映射,业务对象中的属性标有与相应数据库表中目标列的属性映射。

我的验证框架允许我在指定的 ValidationAttribute 的帮助下验证每个字段。

我的框架大量使用属性来自动化大多数繁琐的任务,例如映射和验证。我还可以将新功能作为框架中的新方面。

我的应用程序中的示例业务对象如下所示。

User.cs

[TableMapping("Users")]
public class User : EntityBase

    #region Constructor(s)
    public AppUser()
    
        BookCollection = new BookCollection();
    
    #endregion

    #region Properties

    #region Default Properties - Direct Field Mapping using DataFieldMappingAttribute

    private System.Int32 _UserId;

    private System.String _FirstName;
    private System.String _LastName;
    private System.String _UserName;
    private System.Boolean _IsActive;

    [DataFieldMapping("UserID")]
    [DataObjectFieldAttribute(true, true, false)]
    [NotNullOrEmpty(Message = "UserID From Users Table Is Required.")]
    public override int Id
    
        get
        
            return _UserId;
        
        set
        
            _UserId = value;
        
    

    [DataFieldMapping("UserName")]
    [Searchable]
    [NotNullOrEmpty(Message = "Username Is Required.")]
    public string UserName
    
        get
        
            return _UserName;
        
        set
        
            _UserName = value;
        
    

    [DataFieldMapping("FirstName")]
    [Searchable]
    public string FirstName
    
        get
        
            return _FirstName;
        
        set
        
            _FirstName = value;
        
    

    [DataFieldMapping("LastName")]
    [Searchable]
    public string LastName
    
        get
        
            return _LastName;
        
        set
        
            _LastName = value;
        
    

    [DataFieldMapping("IsActive")]
    public bool IsActive
    
        get
        
            return _IsActive;
        
        set
        
            _IsActive = value;
        
    

    #region One-To-Many Mappings
    public BookCollection Books  get; set; 

    #endregion

    #region Derived Properties
    public string FullName  get  return this.FirstName + " " + this.LastName;  

    #endregion

    #endregion

    public override bool Validate()
    
        bool baseValid = base.Validate();
        bool localValid = Books.Validate();
        return baseValid && localValid;
    

BookCollection.cs

/// <summary>
/// The BookCollection class is designed to work with lists of instances of Book.
/// </summary>
public class BookCollection : EntityCollectionBase<Book>

    /// <summary>
    /// Initializes a new instance of the BookCollection class.
    /// </summary>
    public BookCollection()
    
    

    /// <summary>
    /// Initializes a new instance of the BookCollection class.
    /// </summary>
    public BookCollection (IList<Book> initialList)
        : base(initialList)
    
    

【讨论】:

【参考方案5】:

这里有一个很好的教程,其中包含一个编写良好的分层应用程序的完整源代码控制下载:

http://nerddinnerbook.s3.amazonaws.com/Intro.htm

这不是关于分层架构的教程,但它是一个编写良好的应用程序,并让您深入了解为什么您可能会考虑这种架构。

此外,正如上面仅简要介绍的那样,这是关于保持您的逻辑/存储/表示代码分开,因此如果您必须更改其中之一(例如从 asp.net 前端更改为桌面应用程序) ,做起来并不难。

【讨论】:

【参考方案6】:

***有一个很好的解释:Multitier architecture:

“三层”是一种客户端-服务器架构,其中用户界面、功能流程逻辑(“业务规则”)、计算机数据存储和数据访问作为独立的模块进行开发和维护,通常在不同的平台上进行。

Web 开发使用

在web开发领域,三层常用于指网站,一般是电子商务网站,使用三层构建:

提供静态内容和可能缓存的一些动态内容的前端 Web 服务器。 中间动态内容处理和生成级应用服务器,例如Java EE、ASP.net、php平台。 后端数据库,由数据集和数据库管理系统或 RDBMS 软件组成,用于管理和提供对数据的访问。

【讨论】:

我正在使用visual studio dot net 2005。我可以使用visual sourcesafe Mr. Rubens Farias @Surya,虽然这与您的原始问题无关(它不算作一个等级),是的,您应该使用某种源代码控制工具,例如 SourceSafe 或 TFS跨度> 最好不是 sourcesafe,更新的 scm 工具会是个好主意,特别是如果您刚刚开始。【参考方案7】:

三层架构可以根据上下文有不同的含义。通常,这意味着应用程序中的职责在不同的层之间划分。通常,3 层是指:

表示层”(实际用户界面) 逻辑层(应用程序/业务逻辑) 数据层(数据库、数据存储)

详细信息因应用程序而异。

像往常一样,***有一个很好的概述:http://en.wikipedia.org/wiki/Multitier_architecture

一个简单的例子是一个典型的商业应用:

演示文稿:浏览器或胖客户端 逻辑层:业务逻辑,通常在应用服务器中(基于 J2EE、ASP.NET 或其他) 数据层:数据库,通常是 RDBMS,例如 mysql 或 Oracle

【讨论】:

【参考方案8】:

表示层:放置与用户界面相关的所有内容。 (用户所见)

业务层:与应用程序逻辑相关的一切(来自表示层的信息如何处理)

数据层:提供底层数据源的抽象(来自/去往业务层的信息的存储位置和方式)

每一层都应该尽可能少地了解另一层,并且应该是自上而下的方法:

数据层应该对业务和表示一无所知 业务层应该知道数据而不是表示 演示文稿应该了解业务而不是数据

简单示例:

网站:

Presentation:所有图形事物、用户插入数据的字段、菜单、图片等。 业务:有关数据的所有约束(唯一名称、不带符号的名称、有效日期等)、操作业务对象的方法(创建新用户、添加新订单等) 数据:访问底层数据库的方法。

【讨论】:

【参考方案9】:

三层架构通常包含以下组件:

    客户端浏览器 托管 ASP.NET 应用程序的 Web 服务器 一些后端存储,例如 ASP.NET 应用程序正在访问的数据库

因此,要回答有关如何为 3 层架构编写代码的问题,您需要开发一个与数据存储进行通信的 ASP.NET 应用程序。

【讨论】:

如果您的网站前面有防火墙/负载均衡器,您甚至可以争辩说您拥有 4 层架构。 ;^) 通常不考虑物理网络设备。您可以将客户端浏览器、托管应用程序的 Web 服务器和数据库都放在同一台物理机器上,它仍然是一个 3 层架构。 您会考虑架构中的浏览器部分吗?... 为什么不: 1. Web 服务器提供静态内容或呈现模板; 2、服务器端业务逻辑和动态内容生成; 3. 数据库。 实际上,在经典模型中,拆分会有所不同。客户端浏览器和 Web 服务器都是表示层的一部分(因为 Web 服务器创建 html 和 CSS)。所以web服务器上的app其实既是业务也是表现层的一部分。但当然,你总是可以对术语提出异议...... 如果我在业务层编写连接类,如何获取用户接口层 web.config 文件中的连接字符串。

以上是关于3层架构 - 需要一个例子的主要内容,如果未能解决你的问题,请参考以下文章

MVP架构的一个小例子

三层架构的业务层中是不是可以有多个对象

ASP.NET三层架构DAL层连接数据库的方法

分层架构完整刨析,一个例子带你深入了解

是否值得为小型(ish)应用程序使用 3 层架构

一个JDBC访问oracle数据库表的例子,让你搞清三层架构与MVC框架模式之间的关系,以及满足设计原则的类的结构和各类的职责