MVC基础——市场管理系统(三)Clean Architecture

发布于:2024-12-18 ⋅ 阅读:(45) ⋅ 点赞:(0)


项目地址

  • 教程作者:
  • 教程地址:
  • 代码仓库地址:
  • 所用到的框架和插件:
dbt 
airflow

五、Clean Architecture

  1. usecase driven
  2. plugin based

5.1 user cage driven

5.1.1创建CoreBusiness

业务实体存放的类

  1. 创建一个class library,CoreBusiness
  2. Models文件夹下的Categories.csProducts.cs以及Transactions.cs三个实体类,移动到CoreBusiness类库里,并修改他们的namespace

5.2 创建UseCases

  • 创建UseCases类库

5.2.1 创建CategoriesUseCases

  • 从功能出发,如果我们需要一个处理Categories相关的业务,需要对Categories数据表有哪些操作
  1. 查询出所有的Categories, ViewCategoriesUseCase.cs
  2. 查询单个Category的信息,ViewSelectedCategoryUseCase.cs
  3. 添加单个Category,AddCategoryUseCase.cs
  4. 编辑单个Category,EditCategoryUseCase.cs
  5. 删除单个Category,DeleteCategoryUseCase.cs
1. 创建VeiwCategoriesUseCase获取所有Cagegory
  1. 在UseCases类库里,创建文件夹CategoriesUseCases文件夹
  2. 在该文件夹下添加ViewCategoriesUseCase.cs
  3. ViewCategoriesUseCase.cs 只有一个公共的方法对外使用,因为他的功能显示Category的列表
  4. 添加对CoreBusiness的引用
  5. 创建一个返回所有Category的方法Excute()
public IEnumerable<Category> Excute()
{
}
  1. 使用构造方法,注入一个ICategoryRepository,这里这个接口还没有实现,只是我们知道我们需要用到这个接口提供的方法来获取我们想要的数据,这就是usecase driven的核心
namespace UseCases.CategoriesUseCases
{
    public class ViewCategoriesUseCase
    {
        private readonly ICategoryRepository _categoryRepository;

        public ViewCategoriesUseCase(ICategoryRepository categoryRepository)
        {
            this._categoryRepository = categoryRepository;
        }
        
        public IEnumerable<Category> Excute()
        {
       		//需要用到这个接口给我们提供的GetCategories方法获取数据
            return _categoryRepository.GetCategories();
        }
    }
}
  1. 至此,就完成了一个简单的Use Case Driven,在UseCases层,我们关心,接口哪里来,在哪里实现,只关心我需要这个接口以及接口能解决问题的方法,只是接口的使用者;

5.2.2. 实现ICategoryRepository接口

定义了与 Category 实体相关的操作,所有关于Category的操作都在这个接口上,供给plugins使用

在这里插入图片描述

1 . 在UseCases里创建文件夹DataStorePluginInterfaces
2. 创建ICategoryRepository.cs

using CoreBusiness;

namespace UseCases.DataStorePluginInterfaces
{
    public interface ICategoryRepository
    {
    }
}
  1. 然后通过CategoriesUseCases里创建的方法,来逆向实现接口

在这里插入图片描述

3. 实现获取所有Category的方法
  • ViewCategoriesUseCase.cs里实现GetCategories()方法,该类只负责获取所有的Category列表,单一职责
using CoreBusiness;
using UseCases.DataStorePluginInterfaces;

namespace UseCases.CategoriesUseCases
{
    public class ViewCategoriesUseCase
    {
        private readonly ICategoryRepository _categoryRepository;

        public ViewCategoriesUseCase(ICategoryRepository categoryRepository)
        {
            this._categoryRepository = categoryRepository;
        }

        public IEnumerable<Category> Excute()
        {
            return _categoryRepository.GetCategories();
        }
    }
}


4. 实现获取一个Cagegory的方法
  • 创建ViewSelectedCategoryUseCase.cs,该类只负责获取一个Cagegory

namespace UseCases.CategoriesUseCases
{
    public class ViewSelectedCategoryUseCase
    {
        private readonly ICategoryRepository _categoryRepository;

        public ViewSelectedCategoryUseCase(ICategoryRepository categoryRepository)
        {
            this._categoryRepository = categoryRepository;
        }

        public Category Excute(int categoryId)
        {
            return _categoryRepository.GetCategoryById(categoryId);
        }
    }
}
5. 实现编辑Category的方法
  • 创建EditCategoryUseCase.cs,该类只负责传递一个categoryId和cateogry类,编辑Category
namespace UseCases.CategoriesUseCases
{
    public class EditCategoryUseCase
    {
        private readonly ICategoryRepository _categoryRepository;

        public EditCategoryUseCase(ICategoryRepository categoryRepository)
        {
            this._categoryRepository = categoryRepository;
        }
        public void Excute(int categoryId,Category catogory)
        {
            _categoryRepository.UpdateCategory(categoryId, catogory);
        }
    }
}

6. 实现获取删除Category的方法
  • 创建EditCategoryUseCase.cs,该类只负责通过id删除category
namespace UseCases.CategoriesUseCases
{
    public class DeleteCategoryUseCase
    {
        private readonly ICategoryRepository _categoryRepository;
        public DeleteCategoryUseCase(ICategoryRepository categoryRepository)
        {
            this._categoryRepository = categoryRepository;
        }

        public void Excute(int categoryId)
        {
            _categoryRepository.DeleteCategoryById(categoryId);
        }
    }
}

5.2.3 创建ProductsUseCases

所有的UseCases只有一个公共的方法Excute()的好处:

  1. 单一职责,只要是usecase就只有Excute的方法
  2. 统一入口点都是Excute(),这样以后使用泛型或者反射都易于调用
  • 从功能出发,如果我们需要一个处理products相关的业务,需要对products数据表有哪些操作
  1. 查询出所有的products, ViewProductsUseCase.cs
  2. 查询单个product的信息,ViewSelectedProductUseCase.cs
  3. 添加单个product,AddProductUseCase.cs
  4. 编辑单个product,EditProductUseCase.cs
  5. 删除单个product,DeleteProductUseCase.cs
  • 可以看出来以上都是基础的增删改查,和CategoriesUseCases 基本一样,下面是products自己独有的方法
1. 创建一个AddProductUseCase
  • 这里,我们先不用考虑程序里有什么接口,有什么功能,我们只需要写
    1. 创建一个Excute函数,在所有的UseCase的公共出口
    2. 函数里面里根据功能,这里是添加一个Products,所以直接调用 _productRepository.AddProduct(product);
    3. 通过构造函数从容器中拿我需要repository

在这里插入图片描述

2. 使用快捷键生成IProductRepository接口
  • 使用快捷键 生成接口,将会自动在原目录下生成一个IProductRepository.cs的文件
    在这里插入图片描述
  • IProductRepository.cs
namespace UseCases.ProductsUseCases
{
    public interface IProductRepository
    {
    }
}
  • 将自动该文件移动到DataStorePluginInterfaces文件夹下
3. 通过快捷键生成接口对应的AddProduct方法
  • 继续使用快捷键,往接口里添加AddProduct方法
    在这里插入图片描述
  • 此时,在IProductRepository接口里,我们的方法已经添加成功
using CoreBusiness;

namespace UseCases.ProductsUseCases
{
    public interface IProductRepository
    {
        void AddProduct(Product product);
    }
}
4. 通过同样的方式,将剩下的几个UseCase完成
5. 通过快捷键将UseCase 提取成为接口

不要直接使用具体实现,而是通过接口使用UseCase

  • 使用快捷件, 将所有的UseCases提成接口

在这里插入图片描述

  • 会在同级目录下生成一个IAddProductUseCase.cs文件
using CoreBusiness;

namespace UseCases.ProductsUseCases
{
    public interface IAddProductUseCase
    {
        void Execute(Product product);
    }
}
  • 并且自动,添加了该接口
    在这里插入图片描述
  • 创建interfaces文件夹,在UseCases类库内,将所有关于具体UseCases的用例接口放入

在这里插入图片描述

6. Product的内存Plugin的完善

在这里插入图片描述

  • 需要注意的是: Product商品的一些操作,需要和Category类进行交互,这和Category的plugin的区别;

在这里插入图片描述

5.3 创建Plugins

Plugins就是真正实现ICategoryRepository的地方

5.3.1 实现一个内存存储的plugin

  • 实现内存存储

1.在项目的根目录下创建一个Plugins文件夹,除了在vs里创建,还需要到项目的Folder里创建,因为vs创建的文件夹只是一个视图文件夹,真正的文件夹要在folder里创建

在这里插入图片描述
2. 创建一个Plugins.DateStore.InMemory类库,并在类库里创建CategoriesInMemoryRepository.cs,该类库实现了ICategoryRepository的所有功能

 public class CategoriesInMemoryRepository : ICategoryRepository
  1. 将之前我们使用的内存存储和查询的方法,放到该类库内
    在这里插入图片描述
  2. 由于方法的名称一样,这里直接使用即可
    在这里插入图片描述

5.4 在Controllers里使用IOC

  • 此时,就体现出了,创建具体UseCases的实例接口的好处,我们通过依赖注入是通过接口实例化,而不是直接通过实例,结耦

5.4.1 将项目所用到的所有服务,注册到容器中

  • 在程序入口,将服务注册进来

在这里插入图片描述

5.4.2 添加程序集的引用给UI层

  • 因为UI层,是表现层,所以他需要将所有相关的类库,都引入进来

在这里插入图片描述

5.4.3 从依赖注入容器里获取需要的服务

  1. 通过构造函数从容器里,直接获取需要的服务
  2. 直接通过注册服务的名字,就可以知道服务的功能,并且执行统一的Excute()方法
    在这里插入图片描述

5.4.4 修改之前代码通过使用接口的方法

1. 在Validataion的服务里直接实例化IProductsRepository
  • 由于中间件的生命周期不一样, 在这里我们直接使用接口在Validation的context里直接获取

在这里插入图片描述

2. 创建一个ISellProductUseCase
  • 没创建之前,进行数据的操作直接在Controller里,这是不应该发生的,现在创建了该接口之后,只需要传递相应的数据即可

在这里插入图片描述

5.5 所有容器注册完毕,结构展示

5.5.1 Plugins/CoreBusiness

  • Plugin里是UseCases/DataStorePluginInterfaces里接口的实现,这里对接的各个数据库
  • CoreBuniess里只存放实例类,真实的数据库的实体

在这里插入图片描述

5.5.2 UseCases类库

1. UseCases里的各个组成
  1. interfaces里所有接口都是各个usecase提取出的,作用就是用于注册IOC服务,可以在controller里用;
  2. DataStorePluginInterfaces,各个数据库需要继承的库
    在这里插入图片描述
2. 每个Usecase里的方法和DataStorePluginInterface的关系

真正实现usecase的方法实际上是AddCategory方法,该方法是提取到ICategoryRepository里的实际方法

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到