【问题标题】:How should my business logic interact with my data layer?我的业务逻辑应该如何与我的数据层交互?
【发布时间】:2009-11-23 10:43:14
【问题描述】:

所以我正在制作我的程序草稿。

这是我的计划:

GUI
---
Business Logic
---
Data

您应该能够毫无问题地替换 GUIData 层。 每一层都在观察自己。所以GUI 会从Business logic 调用方法,这些方法总是会返回一个状态,也许还有一些数据。 GUI 应如何响应数据,应始终在 GUI 层中决定。业务逻辑应该对此没有影响。 这样就解决了GUI和业务逻辑的关系。 希望你能关注我。

现在来说一些更具体的东西。 我对数据层的计划是使用数据库。 那么,业务逻辑应该如何从数据层调用方法呢?

也许我应该创建一个枚举,对应于数据层知道的不同硬编码 SQL 查询?

例如

Datalayer.GetResults(Queries.GetAllCustomersIDs);

查询是一个枚举。

如果这是正确的方法,GetResults 应该返回什么?一个字符串数组?但是如果查询有多维数据呢?

然后我应该有 2 个通用方法吗?

Datalayer.GetSingleDimensionResults(SingleDimensionQueries.GetAllCustomersIDs);
Datalayer.GetMultipleDimensionResults(MultiDimensionQueries.GetAllCustomers);

或者我是否应该对每种数据请求进行查询?

Datalayer.GetAllCustomerIDs;
DataLayer.GetAllCustomers;

等等

【问题讨论】:

    标签: architecture


    【解决方案1】:

    一般来说,我的做法是:

    数据层:

    对于数据访问,我为每个对象创建一个接口。每个接口都列出了相关对象的所有公共数据访问方法。为了保存数据,我也为每个对象创建了容器类型,它可以是结构或仅包含数据的简单类。我还依赖语言数据集(如列表)来保存我的数据,因此我没有链接到特定的数据库类型。之后,我创建了一个实现数据接口的类,这个类有所有的SQL并且访问数据库,所以如果数据存储技术发生变化,这是唯一会改变的类。

    业务层:

    是否所有逻辑都包含数据、如何验证、应该调用数据接口中的哪些方法以及调用顺序。此类使用容器(例如列表)接收数据并将数据“发送”到数据存储或 GUI,其中数据类型是我上面提到的容器。

    界面:

    调用业务逻辑方法并显示/格式化数据表示。除了调用业务逻辑的正确方法之外,这里没有其他逻辑。

    容器的小代码示例(C#)

        //Interface for Department class data access. DataStorage assembly
    
        namespace DataStorage
        {
            public interface IDepartmentDS
            {
                void Open();  //Open data conection
                void Close(); //Close data conection
                List<Repositories.Department> List(); //Gets all departments (from data base)
            }
        }
    
    
        //This class holds all data regarded a department. There's no logic here. Repositories assembly
    
        namespace Repositories
        {
            public class Department
            {
                [Browsable(false)]
                public Department()
                {
                }
    
                [Browsable(false)]
                public Department(String Symbol, String Name)
                {
                    this.Symbol = Symbol;
                    this.DeptName = Name;
                }
    
                public Department(Department department)
                {
                    this.Symbol = department.Symbol;
                    this.DeptName = department.DeptName;
                }
    
                [Browsable(false)]
                public String Symbol { get; set; }
    
                public String DeptName { get; set; }
            }
        }
    
    
        //This class implements the data manipulation itself, accessing the real database.
        //However the data exchange outside this class is done via repositories classes and 
        //Generics - Lists mainly
    
        public class DataStorage : IDepartmentDS
        {
           //Here I use to put generic functions to connect with the database, format stored
           //procedure parameters list etc.
    
           //Implementation of the List method declare in the Department Interface
               List<Repositories.Department> IDepartmentDS.List()
                {
                    String query = String.Format("SELECT * FROM {0}", DepartmentTable);
                    int rows = 0;
                    DataSet ds = ExecSqlCommand(query, out rows); //this method is private to this class
    
                    if (ds == null)
                        return null;
    
                    List<Repositories.Department> list = new List<Repositories.Department>();
                    foreach (DataRow row in ds.Tables[0].Rows)
                    {
                        list.Add(new Repositories.Department((String)row[DepFN_Symbol], (String)row[DepFN_DepName]));
                        //DepFN_Symbol and the others are just const variables representing the column index
                    }
    
                    return list;
                }
    
        }
    
    public class DepartmentLogic
    {
       public DepartmentLogic()
       {
          .....
       }
    
       public List<Repositories.Department> GetAllDepartments()
       {
          //Here I create an Instance of the DataStorage but using the Department interface
          //so I restrict the access to Department data methods only. It could be a good 
          //idea here to use the factory pattern.
    
          IDepartmentDS department = (IDepartmentDS) new DataStorage();
          department.Open();
    
          List<Repositories.Department> departments = department.List();
    
          department.Close();
    
          return departments;
       }
    
    }
    

    这个业务逻辑示例确实非常简单,只是展示了如何从存储层检索数据,但只要您可以访问数据,就可以按照您想要的方式操作它。在这里只是一个评论:如果在具有数千个请求的非常繁忙的服务器中实施这个解决方案,也许应该重新考虑这个解决方案,因为它可以使用大量内存。

    从业务逻辑和 UI 的角度来看,所有数据都使用 Lists 等通用容器在模块之间进行通信。所有这些模块之间的链接点是容器类,因此所有类的解耦都不太好。

    UI 向业务逻辑类发出请求,因此它的作用类似于服务提供者。这样做,更改 UI 不会影响下面的类。

    业务逻辑使用通用数据请求数据并将数据发送到数据存储类,因此更改数据库/存储技术应该不会影响它。

    这就是我过去的做法,我正在努力改进它;)

    【讨论】:

    • 能否举个例子,业务逻辑从数据层检索一些数据?
    • 我明白你所说的容器等是什么意思。但我仍然不确定它应该如何检索数据 - 哪种方式是最好的。
    • 我想我被这个吓坏了:“每个接口都列出了相关对象的所有公共数据访问方法。”我真的很感激一些小例子
    • 我放了一些从我编写的应用程序中获得的代码片段。希望对你有帮助
    • 还有一件事。举一个例子,业务逻辑从数据层调用一些方法并检索一些数据。然后我会接受你的回答:)
    【解决方案2】:

    您的数据“层”可能不仅仅是一组语义查询,您应该将其封装在 API 中,否则您的业务逻辑层将不得不对数据层的实现了解太多。您在 GUI 和业务逻辑层之间使用的推理应该适用,并且目的相同。

    【讨论】:

      猜你喜欢
      • 2011-06-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-28
      • 2021-10-18
      • 2012-08-30
      • 1970-01-01
      • 2011-10-23
      • 2011-01-08
      相关资源
      最近更新 更多