一般来说,我的做法是:
数据层:
对于数据访问,我为每个对象创建一个接口。每个接口都列出了相关对象的所有公共数据访问方法。为了保存数据,我也为每个对象创建了容器类型,它可以是结构或仅包含数据的简单类。我还依赖语言数据集(如列表)来保存我的数据,因此我没有链接到特定的数据库类型。之后,我创建了一个实现数据接口的类,这个类有所有的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 不会影响下面的类。
业务逻辑使用通用数据请求数据并将数据发送到数据存储类,因此更改数据库/存储技术应该不会影响它。
这就是我过去的做法,我正在努力改进它;)