0

现在我正在研究一个用 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; }
}

District Entity 类,为什么它的扩展名是 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

4 回答 4

0

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

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

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

现在出现了先有鸡还是先有蛋的问题:您需要重构代码才能对其进行测试,但您现在还没有测试。答案是从“防御性”重构技术开始并进行手动测试。您可以在 Micheal Feather 的《有效使用遗留代码》一书中找到有关这些技术的更多详细信息。如果你需要重构大量遗留代码,你真的应该阅读它。这是一个真正的大开眼界。

对于您的问题:

  1. 没有完美的设计。只有潜在的更好。
  2. 如果应用程序没有任何单元测试,那么这是最大的缺陷。首先介绍测试。另一方面:这些代码片段一点也不差。似乎DistrictDAO有点像District. 也许有一些尝试引入一些域模型。并且:至少DistrictGatewayDatabaseManager注入作为构造函数参数。我见过更糟的。
  3. 是的,try-catch 块可以被视为代码重复,但这并不罕见。您可以尝试通过合理选择异常类来减少 catch 子句。或者您可以使用委托或使用一些 AOP 技术,但这会降低代码的可读性。有关更多信息,请参阅其他问题
  4. 将遗留代码放入一些测试工具中。一个更好的设计将隐含地出现。

任何方式:首先澄清你的老板对重构代码的意思。只是没有目标地重构代码是没有效率的,也不会让老板高兴。

于 2011-09-21T20:31:46.690 回答
0

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

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

N 层架构博客系列(附示例代码)

于 2011-09-21T20:12:57.010 回答
0

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

于 2011-09-21T20:28:19.913 回答
0

完美的?没有这样的事。如果你必须在这里问,那可能是错误的。即使它现在是“完美的”,它也不会是时间和熵掌握它的时候。

当你需要扩展它时,你的表现会如何衡量。如果您的更改直接滑入,那么您做得很好。如果您觉得您正在与遗留代码作斗争以添加更改,请找出您做错了什么并重构它。

缺陷?很难说。我现在没有精力、时间或动力去深入挖掘。

无法弄清楚您所说的#3是什么意思。

典型的分层如下所示,箭头显示依赖关系:

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

每一层都有横切关注点:

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

如果您使用像 Spring 这样的包含面向方面编程的框架,则可以将诸如安全、事务、监控、日志记录等横切关注点视为方面。

于 2011-09-21T19:41:21.950 回答