clean Architecture with springboot

參考來源

來源:https://code-specialist.com/architecture/rest-api-clean-architecture

分層命名

entites layer (命名為 domain)

use cases (命名為 application)

interface adapter (adapter)

framwork & db (plugin)

架構如何分層

  1. Monolithic - divided by packages
  2. Usage of modules - e.g. make use of maven (recommended)

Domain Layer 物件概念

  1. CommonProductFactory
  2. ICommonProuductFactory
  3. CommonProduct
  4. ICommonProduct
  5. SpcProductFactory
  6. SpcProduct
  7. ISpcProduct

test domain

@Test
public void test_givenAbcName_whenNameIsNotValid_thenIsFalse(){
    IProduct product = new CommonProduct("Abc", "Name", "description", 0.5d);

    assertFalse(product.nameIsValid());
}

Applicaiton Layer 物件概念

  1. CommonProductInteractor (use case 邏輯)
  2. CommonProductRegisterInputBoundary (供外部參考的interface)
  3. CommonProductRegisterInputRequestModel (供外部參考的request)
  4. CommonProductRegisterOutputRequestModel (供外部參考的request)
  5. IPresenter (需要依賴的外層物件,用interface達到依賴反轉)
  6. CommonProductRegisterDsGateWay (需要依賴的持久化層物件,用interface達到依賴反轉)
  7. CommonProductRegisterAPIGateWay (需要依賴的外部API物件,用interface達到依賴反轉)

test applicaition 層

mock

public class CommonProductInteractorTest {

    ICommonProductFactory mockedFactory;

    ICommonProductPresenter mockedPresenter;

    ICommonProductRegisterGateway mockedGateway;

    @BeforeEach
    void setup(){
        mockedGateway = Mockito.mock(ICommonProductRegisterGateway.class);
        mockedFactory = Mockito.mock(ICommonProductFactory.class);
        mockedPresenter = Mockito.mock(ICommonProductPresenter.class);
    }
}
test logic
@Test
    void givenValidCommonProductProperties_whenCreate_thenSaveItAndPrepareSuccessView() throws ProductCustomException {
        // ARRANGE
        CommonProductRequestModel requestModel = new CommonProductRequestModel("TestId", "ValidTestName", "Test description", 52.2);
        long timestmap = 1668617824L;
        CommonProduct product = new CommonProduct("001", "ValidName", "Some Description", 25.25d, timestmap);
        CommonProductResponseModel responseModel = new CommonProductResponseModel(product.getId(), product.getName(), product.getDescription(), product.getPrice(), String.valueOf(product.getCreatedAt()));
        CommonProductResponseModel finalResponseModel = new CommonProductResponseModel(product.getId(), product.getName(), product.getDescription(), product.getPrice(), "2022-11-16");

        Mockito.when(mockedGateway.existsById(requestModel.getId())).thenReturn(false);
        Mockito.when(mockedFactory.create(requestModel.getId(), requestModel.getName(), requestModel.getDescription(), requestModel.getPrice())).thenReturn(product);
        Mockito.when(mockedPresenter.prepareSuccessView(responseModel)).thenReturn(finalResponseModel);

        CommonProductInteractor interactor = new CommonProductInteractor(mockedPresenter, mockedFactory, mockedGateway);

        // ACT
        CommonProductResponseModel verifyResponseModel = interactor.create(requestModel);

        // ASSERT
        Assertions.assertEquals("2022-11-16", finalResponseModel.getCreatedAt());

        Mockito.verify(mockedGateway, Mockito.times(1)).save(product);
        Mockito.verify(mockedGateway, Mockito.times(1)).existsById(requestModel.getId());
        Mockito.verify(mockedPresenter, Mockito.times(1)).prepareSuccessView(responseModel);
        Assertions.assertEquals(finalResponseModel.getId(), verifyResponseModel.getId());
        Assertions.assertEquals(finalResponseModel.getName(), verifyResponseModel.getName());
        Assertions.assertEquals(finalResponseModel.getDescription(), verifyResponseModel.getDescription());
        Assertions.assertEquals(finalResponseModel.getPrice(), verifyResponseModel.getPrice());
        Assertions.assertEquals("2022-11-16", verifyResponseModel.getCreatedAt());

    }

Adapter Layer 物件概念

  1. CommonProductRegisterDsGateWayImpl (作為框架持久層的adapter實現gateWay)
  2. CommonProductRegisterAPIGateWayImpl (作為API的adapter實現gateWay)

Plugin Layer 物件概念

  1. springboot Application (psvm)
  2. BeanConfig (依賴注入使用)
  3. restcontroller
  4. service