【问题标题】:Is this a good implementation of a three-layer application design? [closed]这是三层应用程序设计的良好实现吗? [关闭]
【发布时间】:2013-12-13 20:20:35
【问题描述】:

我正试图围绕分层应用程序架构展开思考,在对该主题进行了大量阅读之后,我想出了一些尝试实现数据访问层/业务逻辑层/表示层的代码方法。代码符合我的预期,但我希望得到一些反馈,了解我是否成功实施了这个想法,或者我的思维过程是否存在任何问题。

这是我存储数据的自定义对象:

public class SalesOrderMetaData
{
    private bool isValid;
    public bool IsValid
    {
        get { return isValid; }
        set { isValid = value; }
    }
}

表示层:

protected void Page_Load(object sender, EventArgs e)
{
    // instatiate the BLL object
    SalesOrderBLL salesOrderBLL = new SalesOrderBLL();

    // reuest the custom object from the BLL
    SalesOrderMetaData salesOrderMetaData = salesOrderBLL.GetSalesOrderMetaData("23447");

    // present a value from the custom object to the user
    Label1.Text = salesOrderMetaData.IsValid.ToString();
}

业务逻辑层:

public class SalesOrderBLL
{
    public SalesOrderMetaData GetSalesOrderMetaData(string csono)
    {
        // instantiate the DAL object
        SalesOrderDAL salesOrderDAL = new SalesOrderDAL();

        // request the custom object from the DAL
        SalesOrderMetaData salesOrderMetaData = salesOrderDAL.GetSalesOrderMetaData(csono);

        // return the custom object to the PL
        return salesOrderMetaData;
    }
}

数据访问层:

public class SalesOrderDAL
{
    public SalesOrderMetaData GetSalesOrderMetaData(string csono)
    {
        // instantiate the custom object 
        SalesOrderMetaData salesOrderMetaData = new SalesOrderMetaData();

        // retrieve the data from the data source
        string sql = "IF EXISTS (SELECT * FROM sosord WHERE csono = @csono) SELECT 1 ELSE SELECT 0;";
        SqlParameter param = new SqlParameter("csono", csono);

        // set the custom object property based on the retrieved data
        // SQLUtilities.GetScalar() is a custom method that returns a SqlCommand.ExecuteScalar() object 
        salesOrderMetaData.IsValid = Convert.ToBoolean(SQLUtilities.GetScalar(sql,param)); 

        // return the custom object to the BLL
        return salesOrderMetaData;
    }
}

【问题讨论】:

  • 这个问题似乎是题外话,因为它是关于审查代码。此类问题请参考codereview.stackexchange.com
  • 你可能是对的。我真正追求的不是代码审查,而是我的尝试是否成功实现了这个概念,这是否重要?语义?
  • 代码审查正是如此。有效但需要优化的代码适用于 CodeReview。不起作用的代码适用于 StackOverflow。
  • 好的,我下次从那里开始。谢谢。

标签: c# asp.net oop n-tier-architecture


【解决方案1】:

这是一个好的开始。不过,我会指出一些事情(知道您只是在学习……所以请随时调查这些内容):

1) 当前每一层都与其下一层的实现紧密耦合。通常,在这种情况下,您会“针对接口编写代码”。这意味着您的代码与 contract.. 耦合,而不是实现。不是因为您正在学习而破坏交易......但请记住这一点。

2) 您的数据层都是非常自定义的。通过研究 ORM 的使用,您可以省去很多麻烦。他们需要一些时间来学习。但哇,他们值得维护麻烦。

3) 通常你有代表领域对象的领域模型。很多时候,这些直接对应于数据库表。然后在您的 UI 中,您有 ViewModels 代表正在呈现的 View 中的当前实体。这使您可以灵活地在 ViewModel 中添加基于 UI 的自定义逻辑(验证、格式化等),而无需域模型在其中包含此类特定的 UI 问题。

如果您真的想开始考虑设计和架构(这太棒了!感谢您开始考虑这些东西),那么您绝对应该查看以下内容:

SOLID Principles

ORMs

IoC/Dependency Injection Frameworks

等等。再次,我赞扬您采取实际考虑您的应用程序结构的步骤:)

【讨论】:

  • +1 - 同意 SOLID 和依赖注入应该是 OP 的目标,但令我惊讶的是,有多少“开发人员”甚至没有创建应用程序的层。想到点击事件处理程序中的数据库对象。
【解决方案2】:

您不应允许调用者将您的域对象设置为有效。这是您的代码:

public class SalesOrderMetaData
{
    private bool isValid;
    public bool IsValid
    {
        get { return isValid; }
        set { isValid = value; }
    }
}

任何层都可以将IsValid 属性设置为true,然后当另一个层询问对象是否有效时,它会错误地报告它是有效的。

我建议您将IsValid 属性设为只读(仅限get)。内部isValid变量的更新应该通过Validate()这样的方法来完成,像这样:

public class SalesOrderMetaData
{
    private bool isValid;
    public bool IsValid
    {
        get { return isValid; }
    }
}

public void Validate()
{
    // Check business rules here and then set isValid value to true or false
}

现在其他层不能对域对象撒谎并说它可能无效,而是可以要求通过Validate 方法验证域对象。

使用Validate 方法不是处理此问题的唯一方法,只是想让您了解如何处理它。

层间交互的代码看起来不错。

【讨论】:

  • 太棒了,谢谢。我对此很担心,但不知道如何解决。
  • @brainbolt - 当然,没问题。祝你的编码好运。 :-)
  • 那么您是否建议仅将原始数据返回到 BLL,可能以另一个对象的形式,然后在验证原始数据后在 BLL 中实例化 SalesOrderMetaData 对象?我可以看到这是有道理的,因为从概念上讲,SalesOrderMetaData 确实更像是一个业务逻辑对象而不是数据对象。
  • @brainbolt - 是的,这是一种方法。现在您正在深入研究 DTO(数据传输对象)、业务/域对象和最终视图模型对象之间的区别。不幸的是,尽管有些人会告诉你什么,但对于完美的分层架构来说,并没有什么灵丹妙药可以在每种情况下都发挥最佳作用。最好沿着你要走的路走,找出哪些行之有效,哪些行不通。在某些情况下,经验和反复试验确实无可替代。正如其他人所说,您正在考虑/担心架构这一事实本身就很棒。
  • 明白。非常感谢。
【解决方案3】:

到目前为止,您已经展示了一种基本的 n 层方法,这是一个好的开始。通过首先用实体框架代码替换您的数据访问层来构建它可能会更容易。还可以将 Unity 等控制容器的反转视为进一步分离功能/关注点的一种方式

团结在这里:http://msdn.microsoft.com/en-us/library/dn170416.aspx

这里的实体框架:http://msdn.microsoft.com/en-us/data/ee712907

【讨论】:

    猜你喜欢
    • 2022-10-21
    • 2015-03-11
    • 1970-01-01
    • 2012-09-08
    • 2017-01-09
    • 1970-01-01
    • 1970-01-01
    • 2012-09-12
    • 2011-01-06
    相关资源
    最近更新 更多