当我们说仓库接口应该‘关注点分离’时,这意味着什么?请给出一个实例来说明如何在代码中实现这一点。

当我们说仓库接口应该‘关注点分离’时,意味着仓库接口应当专注于数据访问操作,而不应涉及与数据访问无关的其他业务逻辑。这样的设计有助于提高代码的可维护性、可测试性和可扩展性,同时也使得职责更加明确,使得团队成员能够更容易地理解各个部分的代码。具体来说,仓库接口应该只提供简单的数据访问方法(例如查询、插入、更新和删除),而不应该包含复杂的业务逻辑。复杂业务逻辑应该由服务层来处理。

实例:一个简单的待办事项应用程序

假设我们正在开发一个简单的待办事项应用,该应用允许用户创建、更新和删除待办事项。在这个应用中,我们希望能够将数据访问逻辑与业务逻辑分开。

仓库接口定义

首先,我们定义一个仓库接口 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;
    }
}

通过这种方式,我们实现了关注点分离。仓库接口只负责数据访问,而服务层则处理业务逻辑。这种设计使得代码更加模块化,易于测试和维护。