层架构的最佳实践是什么?

时间:2011-09-21 19:31:12

标签: c# refactoring data-access-layer business-logic-layer

现在我正在开发一个用VB6开发的非常大的银行解决方案。该应用程序是基于表单的,并且缺乏分层体系结构(数据访问,业务逻辑和表单操作的所有代码都在单个表单类中)。我现在的工作是重构这段代码。我正在用C#编写一个合适的业务逻辑层和数据访问层,表单将保留在VB中。

以下是代码段:

public class DistrictDAO
{
    public string Id{get;set;}
    public string DistrictName { get; set; }
    public string CountryId { get; set; }
    public DateTime SetDate { get; set; }
    public string UserName { get; set; }
    public char StatusFlag { get; set; }
}

地区实体类,为什么它的扩展名为DAO,我不清楚。

 public class DistrictGateway
{
    #region private variable
    private DatabaseManager _databaseManager;
    #endregion

    #region Constructor
    public DistrictGateway(DatabaseManager databaseManager) {
        _databaseManager = databaseManager;
    }
    #endregion

    #region private methods
    private void SetDistrictToList(List<DistrictDAO> dataTable, int index, DistrictDAO district){
        // here is some code for inserting 
    }    
    #endregion

    #region public methods
        try
        {
        /*
         query and rest of the codes
         */    

        }
        catch (SqlException sqlException)
        {
            Console.WriteLine(sqlException.Message);
            throw;
        }
        catch (FormatException formateException)
        {
            Console.WriteLine(formateException.Message);
            throw;
        }
        finally {
            _databaseManager.ConnectToDatabase();
        }


    public void InsertDistrict() { 
        // all query to insert object
    }

    public void UpdateDistrict() { 

    }
    #endregion
}

DistrictGateway类负责数据库查询处理 现在是业务层。

  public class District
{
    public string Id { get; set; }
    public string DistrictName { get; set; }
    public string CountryId { get; set; }
}


public class DistrictManager
{
    #region private variable
    private DatabaseManager _databaseManager;
    private DistrictGateway _districtGateway;
    #endregion

    #region Constructor
    public DistrictManager() { 
        // Instantiate the private variable using utitlity classes
    }
    #endregion

    #region private method
    private District TransformDistrictBLLToDL(DistrictDAO districtDAO) { 

        // return converted district with lots of coding here
    }

    private DistrictDAO TransformDistrictDLToBLL(District district)
    {

        // return converted DistrictDAO with lots of coding here
    }

    private List<District> TransformDistrictBLLToDL(List<DistrictDAO> districtDAOList)
    {

        // return converted district with lots of coding here
    }

    private List<DistrictDAO> TransformDistrictDLToBLL(List<District> district)
    {

        // return converted DistrictDAO with lots of coding here
    }


    #endregion

    #region public methods
    public List<District> GetDistrict() {
        try
        {
            _databaseManager.ConnectToDatabase();
          return TransformDistrictBLLToDL(  _districtGateway.GetDistrict());

        }
        catch (SqlException sqlException)
        {
            Console.WriteLine(sqlException.Message);
            throw;
        }
        catch (FormatException formateException)
        {
            Console.WriteLine(formateException.Message);
            throw;
        }
        finally {
            _databaseManager.ConnectToDatabase();
        }
    }

    #endregion

这是业务层的代码。

我的问题是:

  1. 这是一个完美的设计吗?
  2. 如果没有,这里有什么缺陷?
  3. 我认为,此代码包含重复的try catch块
  4. 这项实施的优秀设计

4 个答案:

答案 0 :(得分:0)

完美?没有这样的事。如果你在这里问,那可能是错的。即使它现在是“完美的”,也不会有一次时间和熵得到它。

当你需要延长它时,衡量你的表现会如何。如果您的更改正确插入,则表现良好。如果你觉得你正在与遗留代码进行对抗以添加更改,请弄清楚你做错了什么并重构它。

缺陷?这很难说。我现在没有足够的精力,时间或动力来深入挖掘。

无法弄明白你的意思#3。

典型的分层看起来像这样,箭头显示依赖关系:

view <- controller -> service +-> model <- persistence  (service knows about persistence)

每一层都存在交叉问题:

  • view了解演示文稿,样式和本地化。它可以进行任何验证以改善用户体验,但不包括业务规则。
  • 控制器与视图密切相关。它关注来自视图的请求的绑定和验证,路由到适当的服务,错误处理以及路由到下一个视图。而已。业务逻辑属于服务,因为您希望它与Web,平板电脑,移动设备等相同。
  • 服务是业务逻辑所在的位置。它担心根据业务规则进行验证,并与模型和持久层协作以完成用例。它了解用例,工作单元和事务。
  • 模型对象可以是值对象,如果您更喜欢更实用的样式,或者如果您愿意,可以获得更丰富的业务逻辑。
  • 持久性隔离所有数据库交互。

如果您使用包含面向方面编程的Spring等框架,您可以考虑安全性,事务,监视,日志记录等交叉问题。

答案 1 :(得分:0)

虽然,你在这里并没有真正提出具体问题,但似乎你可能只需要一些一般指导就可以让你走上正确的道路。由于我们没有像您一样对整个应用程序进行深入的了解,因此为您建议一种方法是很奇怪的。

n层架构最近似乎是一个受欢迎的问题,但它引发了我写一个关于它的博客系列。检查这些SO问题和博客文章。我认为他们会对你有很大帮助。

N-Tier架构博客系列(带示例代码)

答案 2 :(得分:0)

对于一个大项目,我会推荐MVVM模式,这样你就可以完全测试你的代码了,以后扩展或更改部分代码会更容易。即使您可以更改UI,也无需更改其他图层中的代码。

答案 3 :(得分:0)

如果你的工作是要重构代码,那么首先问你的老板你是否应该真的,应该重构它添加它的功能。在这两种情况下,您都需要围绕该代码自动化测试工具。如果你很幸运,你应该添加它的功能,那么你至少有一个起点和目标。否则你将不得不自己选择起点而没有目标。你可以无休止地重构代码。没有目标,这可能会非常令人沮丧。

重构代码而无需测试灾难的配方。重构代码意味着改进其结构而不改变其行为。如果你不做任何测试,你不能确定你没有破坏某些东西。由于您需要定期和大量测试,因此这些测试必须是自动化的。否则你会花太多时间进行手动测试。

遗留代码很难进入某些测试工具。您需要对其进行修改才能使其可测试。您围绕代码包装测试的努力将隐式地导致一些分层的代码结构。

现在有一个鸡蛋和鸡蛋问题:你需要重构代码才能测试它,但你现在没有测试。答案是从“防御性”重构技术开始并进行手动测试。您可以在Micheal Feather的书Working Effectively with Legacy Code中找到有关这些技巧的更多详细信息。如果你需要重构很多遗留代码,你应该真正阅读它。这真是令人大开眼界。

问题:

  1. 没有完美的设计。只有可能更好的。
  2. 如果应用程序没有任何单元测试,那么这是最大的缺陷。首先介绍测试。另一方面:那些代码片段并没有那么糟糕。似乎DistrictDAO类似District的技术版本。也许有一些尝试引入一些领域模型。并且:至少DistrictGatewayDatabaseManager作为构造函数参数注入。我看到的情况更糟。
  3. 是的,try-catch块可以看作代码重复,但这并不罕见。您可以尝试通过合理选择Exception类来减少catch子句。或者你可以使用委托或使用一些AOP技术,但这会使代码的可读性降低。有关详情,请参阅this other question
  4. 将遗留代码放入某些测试工具中。一个更好的设计将隐含出现。
  5. 任何方式:首先澄清你的老板对重构代码的意义。只是在没有某些目标的情况下重构代码并不高效,也不会让老板高兴。