组合和存储库模式

Compositon and Repository pattern

我想通过注入在 CategoryRepository 内部使用 BloggingRepository class,并通过 CategoryRepository

访问控制器中的 BloggingRepository 方法

但是我无法实现这个,因为我无法访问 CategoryController 中的 bloggingRepo 字段, 所以我决定通过继承来实现。

由于我对oop没有经验,如果你能指导我为什么这种方法不起作用以及什么是合适的方法,我将不胜感激

在图片中,第一个设计有效,但第二个无效 class diagram image

我想在CategoryController的SaveCategory中使用BloggingRepository的Add方法

public interface IBloggingRepository
    {
        void Add<T>(T entity) where T : class;
        void Delete<T>(T entity) where T : class;
        Task<bool> SaveAll();
    }


 public interface ICategoryRepository : IBloggingRepository
    {
        Task<Category> GetCategory(int id);
    }


public class BloggingRepository : IBloggingRepository
    {
        private readonly DataContext _context;

        public BloggingRepository(DataContext context )
        {
            _context = context;
        }
        public void Add<T>(T entity) where T : class
        {
            _context.Add(entity);
        }

    }


 public class CategoryRepository : ICategoryRepository
    {
        private readonly DataContext _context;

        public readonly IBloggingRepository bloggingRepo;

        public CategoryRepository(DataContext context, IBloggingRepository bloggingRepository) 
        {
            _context = context;
            bloggingRepo = bloggingRepository;
        }
    }


public class CategoryController : Controller
    {
        private readonly ICategoryRepository _categoryRepo;

        public CategoryController(ICategoryRepository categoryRepo)
        {
            _categoryRepo = categoryRepo;
        }

        public async Task<IActionResult> SaveCategory()
        {
           // _categoryRepo.bloggingRepo.Add();
        }
    }



//Startup.cs
services.AddScoped<IBloggingRepository, BloggingRepository>();
services.AddScoped<ICategoryRepository, CategoryRepository>();

您的界面应描述您希望公开的所有方法。您的接口描述了给定的 class 将实现什么,而不是 如何实现 ,因此不会暴露 class 的状态。这很好,因为它允许您从该接口继承多个 class 并以不同的方式实现相同的方法。

在您的情况下,您希望能够从您的 CategoryRepository "Add"。幸运的是,您已经有了一个接口,IBloggingRepository。

如果您想要在 ICategoryRepository 的 IBloggingRepository 中找到相同的方法,也只需实现该接口即可!就是这么简单。

方法 1(不起作用): 在此方法中,CategoryRepository 将实现这两​​个接口,因此 CategoryRepository 必须公开 Add 方法。这也提供了从 class 外部隐藏 IBloggingRepository 的能力,以便隐藏状态。但是,这不起作用。为什么?只有 CategoryRepository class 实现了 ICategoryRepository 和 IBloggingRepository。 ICategoryRepository 未实现 IBloggingRepository,因此 Add 方法未在 ICategoryRepository 接口中公开,而这正是您的控制器中使用的方法。

// Implementation of the repository
// Does not expose Add to the ICategoryRepository !!!
public class CategoryRepository : ICategoryRepository, IBloggingRepository
{
    private readonly DataContext _context;

    private readonly IBloggingRepository _bloggingRepo;

    public CategoryRepository(DataContext context, IBloggingRepository bloggingRepository) 
    {
        _context = context;
        _bloggingRepo = bloggingRepository;
    }
    // The implementation of the Add method
    public void Add<T>(T entity) where T : class
    {
        _bloggingRepo.Add(entity);
    }
}

方法二(正确答案): 通过这种方式,我们强制每个 ICategoryRepository 都必须实现 IBloggingRepository。这与方法 1 不同,因为第一种方法并不意味着每个 ICategoryRepository 都将实现 IBloggingRepostiory。

// Exposes the IBloggingRepository methods to ICategoryRepository
public interface ICategoryRepository : IBloggingRepository
{
}

// Implementation of the repository
public class CategoryRepository : ICategoryRepository
{
    private readonly DataContext _context;

    private readonly IBloggingRepository _bloggingRepo;

    public CategoryRepository(DataContext context, IBloggingRepository bloggingRepository) 
    {
        _context = context;
        _bloggingRepo = bloggingRepository;
    }
    // The implementation of the Add method
    public void Add<T>(T entity) where T : class
    {
        _bloggingRepo.Add(entity);
    }
}

演示:

// Some model to be added to the repository
// Just for demonstration purposes
public class Blog
{
    public Blog() { }
}


public class CategoryController : Controller
{
    private readonly ICategoryRepository _categoryRepo;

    public CategoryController(ICategoryRepository categoryRepo)
    {
        _categoryRepo = categoryRepo;
    }

    public async Task<IActionResult> SaveCategory()
    {
       // _categoryRepo.bloggingRepo.Add();
       return await Task.Run(() => 
       {
           Blog blog = new Blog();
           _categoryRepo.Add(blog);
           // return IActionResult;

       }).ConfigureAwait(false);
    }
}

关于我为什么使用 ConfigureAwait(false) 的注释:

As a general rule, every piece of code that is not in a view model and/or that does not need to go back on the main thread should use ConfigureAwait false.