文章目錄
- 項目地址
- 五、Clean Architecture
- 5.1 user cage driven
- 5.1.1創建CoreBusiness
- 5.2 創建UseCases
- 5.2.1 創建CategoriesUseCases
- 1. 創建`VeiwCategoriesUseCase`獲取所有Cagegory
- 5.2.2. 實現ICategoryRepository接口
- 3. 實現獲取所有Category的方法
- 4. 實現獲取一個Cagegory的方法
- 5. 實現編輯Category的方法
- 6. 實現獲取刪除Category的方法
- 5.2.3 創建ProductsUseCases
- 1. 創建一個AddProductUseCase
- 2. 使用快捷鍵生成IProductRepository接口
- 3. 通過快捷鍵生成接口對應的AddProduct方法
- 4. 通過同樣的方式,將剩下的幾個UseCase完成
- 5. 通過快捷鍵將UseCase 提取成為接口
- 6. Product的內存Plugin的完善
- 5.3 創建Plugins
- 5.3.1 實現一個內存存儲的plugin
- 5.4 在Controllers里使用IOC
- 5.4.1 將項目所用到的所有服務,注冊到容器中
- 5.4.2 添加程序集的引用給UI層
- 5.4.3 從依賴注入容器里獲取需要的服務
- 5.4.4 修改之前代碼通過使用接口的方法
- 1. 在Validataion的服務里直接實例化IProductsRepository
- 2. 創建一個ISellProductUseCase
- 5.5 所有容器注冊完畢,結構展示
- 5.5.1 Plugins/CoreBusiness
- 5.5.2 UseCases類庫
- 1. UseCases里的各個組成
- 2. 每個Usecase里的方法和DataStorePluginInterface的關系
項目地址
- 教程作者:
- 教程地址:
- 代碼倉庫地址:
- 所用到的框架和插件:
dbt
airflow
五、Clean Architecture
- usecase driven
- plugin based
5.1 user cage driven
5.1.1創建CoreBusiness
業務實體存放的類
- 創建一個class library,
CoreBusiness
- 將
Models
文件夾下的Categories.cs
和Products.cs
以及Transactions.cs
三個實體類,移動到CoreBusiness類庫里,并修改他們的namespace
5.2 創建UseCases
- 創建
UseCases
類庫
5.2.1 創建CategoriesUseCases
- 從功能出發,如果我們需要一個處理Categories相關的業務,需要對Categories數據表有哪些操作
- 查詢出所有的Categories, ViewCategoriesUseCase.cs
- 查詢單個Category的信息,ViewSelectedCategoryUseCase.cs
- 添加單個Category,AddCategoryUseCase.cs
- 編輯單個Category,EditCategoryUseCase.cs
- 刪除單個Category,DeleteCategoryUseCase.cs
1. 創建VeiwCategoriesUseCase
獲取所有Cagegory
- 在UseCases類庫里,創建文件夾
CategoriesUseCases
文件夾 - 在該文件夾下添加
ViewCategoriesUseCase.cs
- ViewCategoriesUseCase.cs 只有一個公共的方法對外使用,因為他的功能顯示Category的列表
- 添加對CoreBusiness的引用
- 創建一個返回所有Category的方法Excute()
public IEnumerable<Category> Excute()
{
}
- 使用構造方法,注入一個
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();}}
}
- 至此,就完成了一個簡單的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{}
}
- 然后通過
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()的好處:
- 單一職責,只要是usecase就只有Excute的方法
- 統一入口點都是Excute(),這樣以后使用泛型或者反射都易于調用
- 從功能出發,如果我們需要一個處理products相關的業務,需要對products數據表有哪些操作
- 查詢出所有的products, ViewProductsUseCase.cs
- 查詢單個product的信息,ViewSelectedProductUseCase.cs
- 添加單個product,AddProductUseCase.cs
- 編輯單個product,EditProductUseCase.cs
- 刪除單個product,DeleteProductUseCase.cs
- 可以看出來以上都是基礎的增刪改查,和CategoriesUseCases 基本一樣,下面是products自己獨有的方法
1. 創建一個AddProductUseCase
- 這里,我們先不用考慮程序里有什么接口,有什么功能,我們只需要寫
- 創建一個Excute函數,在所有的UseCase的公共出口
- 函數里面里根據功能,這里是添加一個Products,所以直接調用
_productRepository.AddProduct(product);
- 通過構造函數從容器中拿我需要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
- 將之前我們使用的內存存儲和查詢的方法,放到該類庫內
- 由于方法的名稱一樣,這里直接使用即可
5.4 在Controllers里使用IOC
- 此時,就體現出了,創建具體UseCases的實例接口的好處,我們通過依賴注入是通過接口實例化,而不是直接通過實例,結耦
5.4.1 將項目所用到的所有服務,注冊到容器中
- 在程序入口,將服務注冊進來
5.4.2 添加程序集的引用給UI層
- 因為UI層,是表現層,所以他需要將所有相關的類庫,都引入進來
5.4.3 從依賴注入容器里獲取需要的服務
- 通過構造函數從容器里,直接獲取需要的服務
- 直接通過注冊服務的名字,就可以知道服務的功能,并且執行統一的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里的各個組成
- interfaces里所有接口都是各個usecase提取出的,作用就是用于注冊IOC服務,可以在controller里用;
- DataStorePluginInterfaces,各個數據庫需要繼承的庫
2. 每個Usecase里的方法和DataStorePluginInterface的關系
真正實現usecase的方法實際上是AddCategory方法,該方法是提取到ICategoryRepository里的實際方法