当我们说仓库接口应该‘关注点分离’时,这意味着什么?请给出一个实例来说明如何在代码中实现这一点。
当我们说仓库接口应该‘关注点分离’时,意味着仓库接口应当专注于数据访问操作,而不应涉及与数据访问无关的其他业务逻辑。这样的设计有助于提高代码的可维护性、可测试性和可扩展性,同时也使得职责更加明确,使得团队成员能够更容易地理解各个部分的代码。具体来说,仓库接口应该只提供简单的数据访问方法(例如查询、插入、更新和删除),而不应该包含复杂的业务逻辑。复杂业务逻辑应该由服务层来处理。
实例:一个简单的待办事项应用程序
假设我们正在开发一个简单的待办事项应用,该应用允许用户创建、更新和删除待办事项。在这个应用中,我们希望能够将数据访问逻辑与业务逻辑分开。
仓库接口定义
首先,我们定义一个仓库接口 ITodoRepository,这个接口只负责数据访问操作:
public interface ITodoRepository
{
Task AddAsync(TodoItem item);
Task<List<TodoItem>> GetAllAsync();
Task<TodoItem> GetByIdAsync(int id);
Task UpdateAsync(TodoItem item);
Task DeleteAsync(int id);
}
仓库实现
接下来,我们实现这个接口。为了简单起见,我们可以使用一个内存中的列表来模拟数据存储:
public class TodoRepository : ITodoRepository
{
private readonly List<TodoItem> _todos = new List<TodoItem>();
private int _nextId = 1;
public async Task AddAsync(TodoItem item)
{
item.Id = _nextId++;
_todos.Add(item);
}
public async Task<List<TodoItem>> GetAllAsync()
{
return _todos;
}
public async Task<TodoItem> GetByIdAsync(int id)
{
return _todos.FirstOrDefault(t => t.Id == id);
}
public async Task UpdateAsync(TodoItem item)
{
var existingItem = await GetByIdAsync(item.Id);
if (existingItem != null)
{
existingItem.Title = item.Title;
existingItem.Completed = item.Completed;
}
}
public async Task DeleteAsync(int id)
{
var existingItem = await GetByIdAsync(id);
if (existingItem != null)
{
_todos.Remove(existingItem);
}
}
}
服务层
然后,我们在服务层处理业务逻辑。服务层会调用仓库接口来访问数据,并在此基础上实现更复杂的业务逻辑。例如,我们可以通过服务层来确保一个待办事项的标题不能为空,并且在删除待办事项时检查用户是否有权限删除该事项:
public class TodoService
{
private readonly ITodoRepository _todoRepository;
public TodoService(ITodoRepository todoRepository)
{
_todoRepository = todoRepository;
}
public async Task AddTodoAsync(TodoItem item)
{
if (string.IsNullOrEmpty(item.Title))
{
throw new ArgumentException("Title cannot be null or empty", nameof(item.Title));
}
await _todoRepository.AddAsync(item);
}
public async Task<List<TodoItem>> GetTodosAsync()
{
return await _todoRepository.GetAllAsync();
}
public async Task<TodoItem> GetTodoByIdAsync(int id)
{
return await _todoRepository.GetByIdAsync(id);
}
public async Task UpdateTodoAsync(TodoItem item)
{
if (string.IsNullOrEmpty(item.Title))
{
throw new ArgumentException("Title cannot be null or empty", nameof(item.Title));
}
await _todoRepository.UpdateAsync(item);
}
public async Task DeleteTodoAsync(int id)
{
var item = await _todoRepository.GetByIdAsync(id);
if (item == null)
{
throw new InvalidOperationException("Todo item not found");
}
// Check if the user has permission to delete (this is just an example)
if (!HasPermissionToDelete(item))
{
throw new UnauthorizedAccessException("User does not have permission to delete this todo item");
}
await _todoRepository.DeleteAsync(id);
}
private bool HasPermissionToDelete(TodoItem item)
{
// Implement permission check logic here
return true;
}
}
通过这种方式,我们实现了关注点分离。仓库接口只负责数据访问,而服务层则处理业务逻辑。这种设计使得代码更加模块化,易于测试和维护。