Tôi có nên sử dụng một lớp giữa dịch vụ và kho lưu trữ cho một kiến ​​trúc sạch - Spring


9

Tôi đang làm việc trong một kiến ​​trúc, nó sẽ cung cấp một api còn lại cho ứng dụng web và ứng dụng di động. Tôi đang sử dụng Spring (spring mvc, spring data jpa, ... vv). Mô hình miền được mã hóa với đặc tả JPA.

Tôi đang cố gắng áp dụng một số khái niệm về kiến ​​trúc sạch ( https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-arch architecture.html ). Không phải tất cả, bởi vì tôi sẽ giữ mô hình miền jpa.

Dòng chảy thực tế qua các lớp là thế này:

Giao diện người dùng <-> Dịch vụ API -> Dịch vụ -> Kho lưu trữ -> DB

  • Giao diện người dùng : ứng dụng web, ứng dụng di động
  • Dịch vụ API : Bộ điều khiển nghỉ, ở đây tôi sử dụng bộ chuyển đổi và dịch vụ cuộc gọi và cuộc gọi
  • Dịch vụ : Giao diện với các triển khai và chúng chứa logic nghiệp vụ
  • Kho lưu trữ : Các giao diện kho lưu trữ với việc triển khai tự động (được thực hiện bởi dữ liệu mùa xuân jpa) có hoạt động CRUD và có thể một số truy vấn sql

Tôi nghi ngờ: Tôi có nên sử dụng một lớp bổ sung giữa dịch vụ và kho lưu trữ không?

Tôi đang lên kế hoạch cho luồng mới này:

Giao diện người dùng <-> Dịch vụ API -> Dịch vụ -> Kiên trì -> Kho lưu trữ -> DB

Tại sao phải sử dụng lớp kiên trì này? Như đã nói trong bài viết kiến ​​trúc sạch, tôi muốn có một triển khai dịch vụ (logic nghiệp vụ hoặc trường hợp sử dụng) truy cập vào lớp kiên trì bất khả tri. Và không cần thay đổi nếu tôi quyết định sử dụng một mẫu "truy cập dữ liệu" khác, ví dụ nếu tôi quyết định ngừng sử dụng kho lưu trữ.

class ProductServiceImpl implements ProductService {
    ProductRepository productRepository;
    void save(Product product) {
        // do business logic
        productRepository.save(product)
    }
}

Vì vậy, tôi nghĩ rằng sử dụng một lớp kiên trì như thế này:

class ProductServiceImpl implements ProductService {
    ProductPersistence productPersistence;
    void save(Product product) {
        // do business logic
        productPersistence.save(product)
    }
}

và thực hiện lớp kiên trì như thế này:

class ProductPersistenceImpl implements ProductPersistence {
    ProductRepository productRepository;
    void save(Product product) {
        productRepository.save(product)
    }
}

Vì vậy, tôi chỉ cần thay đổi việc triển khai lớp kiên trì, rời khỏi dịch vụ mà không thay đổi. Kết hợp với thực tế là Kho lưu trữ có liên quan với khung.

Bạn nghĩ sao? Cảm ơn.


3
kho lưu trữ là lớp trừu tượng. thêm một cái khác không giúp được gì
Ewan

Ồ, nhưng tôi sẽ phải sử dụng giao diện được đề xuất bởi Spring, ý tôi là, tên phương thức kho lưu trữ. Và nếu tôi muốn thay đổi kho lưu trữ, tôi sẽ phải giữ các tên gọi, Không?
Alejandro

đối với tôi có vẻ như kho lưu trữ mùa xuân không buộc bạn phải phơi bày các vật thể mùa xuân. Chỉ cần sử dụng nó để thực hiện giao diện bất khả tri
Ewan

Câu trả lời:


6

Giao diện người dùng <-> Dịch vụ API -> Dịch vụ -> Kho lưu trữ -> DB

Đúng. Đây là thiết kế cơ bản bằng cách phân tách các mối quan tâm được đề xuất bởi Spring Framework. Vì vậy, bạn đang ở trong " mùa xuân đúng cách ".

Mặc dù Kho lưu trữ thường được sử dụng làm DAO, nhưng sự thật là các nhà phát triển Spring đã lấy khái niệm về Kho lưu trữ từ DDD của Eric Evans. Các giao diện kho lưu trữ thường trông rất giống với DAO vì các phương thức CRUD và vì nhiều nhà phát triển cố gắng tạo giao diện của kho lưu trữ để cuối cùng, chúng không có sự khác biệt với EntityManager (DAO thật ở đây) 1 nhưng hỗ trợ truy vấn và tiêu chí.

Được dịch sang các thành phần của Spring, thiết kế của bạn tương tự như

@RestController > @Service > @Repository >  EntityManager

Kho lưu trữ đã là một sự trừu tượng giữa các dịch vụ và lưu trữ dữ liệu. Khi chúng tôi mở rộng giao diện kho lưu trữ Spring Data JPA, chúng tôi đang thực hiện thiết kế này hoàn toàn. Khi chúng tôi làm điều này, chúng tôi đang trả một khoản thuế: khớp nối chặt chẽ với các thành phần của Spring. Ngoài ra, chúng tôi phá vỡ LoD và YAGNI bằng cách kế thừa một số phương thức mà chúng tôi có thể không cần hoặc không muốn. Chưa kể rằng một giao diện như vậy không cung cấp cho chúng tôi bất kỳ cái nhìn sâu sắc có giá trị nào về nhu cầu tên miền mà họ phục vụ.

Điều đó nói rằng, việc mở rộng kho lưu trữ Spring Data JPA là không bắt buộc và bạn có thể tránh những sự đánh đổi này bằng cách thực hiện một hệ thống phân cấp các lớp đơn giản và tùy chỉnh hơn.

    @Repository
    public class MyRepositoryImpl implements MyRepository{
        private EntityManager em;

        @Autowire
        public MyRepository (EntityManager em){    
             this.em = em;
        }

        //Interface implentation
        //...
    }

Thay đổi nguồn dữ liệu bây giờ chỉ cần thực hiện mới thay thế EntityManager bằng một nguồn dữ liệu khác .

    //@RestController > @Service > @Repository >  RestTemplate

    @Repository
    public class MyRepositoryImpl implements MyRepository{
        private RestTemplate rt;

        @Autowire 
        public MyRepository (RestTemplate rt){    
             this.rt = rt;
        }

        //Interface implentation
        //...
    }
    //@RestController > @Service > @Repository >  File

    @Repository
    public class MyRepositoryImpl implements MyRepository{

        private File file; 
        public MyRepository (File file){    
            this.file = file;
        }

        //Interface implentation
        //...
    }
    //@RestController > @Service > @Repository >  SoapWSClient

    @Repository
    public class MyRepositoryImpl implements MyRepository{

        private MyWebServiceClient wsClient; 

        @Autowire
        public MyRepository (MyWebServiceClient  wsClient){    
               this.wsClient = wsClient;
        }

        //Interface implentation
        //...
    }

và như thế. 2

Quay lại câu hỏi, liệu bạn có nên thêm một lớp trừu tượng nữa không, tôi sẽ nói không bởi vì nó không cần thiết. Ví dụ của bạn chỉ thêm phức tạp hơn. Lớp bạn đề xuất sẽ kết thúc dưới dạng proxy giữa các dịch vụkho lưu trữ hoặc là lớp lưu trữ giả dịch vụ khi cần logic cụ thể và bạn không đặt nó ở đâu.


1: Không giống như nhiều nhà phát triển nghĩ, giao diện kho lưu trữ có thể hoàn toàn khác nhau vì mỗi kho lưu trữ phục vụ các nhu cầu tên miền khác nhau. Trong Spring Data JPA, vai trò DAO được thực hiện bởi EntityManager . Nó quản lý các phiên, quyền truy cập vào DataSource , ánh xạ , v.v.

2: Một giải pháp tương tự là tăng cường các giao diện kho lưu trữ của Spring trộn chúng với các giao diện tùy chỉnh. Để biết thêm thông tin, hãy tìm BaseRep repositoryFactoryBean@NoRep repositoryBean . Tuy nhiên, tôi đã tìm thấy cách tiếp cận này rườm rà và khó hiểu.


3

Cách tốt nhất để chứng minh rằng một thiết kế linh hoạt là uốn cong nó.

Bạn muốn một vị trí trong mã của bạn chịu trách nhiệm cho sự bền bỉ nhưng không bị ràng buộc với ý tưởng sử dụng một kho lưu trữ. Khỏe. Nó không làm gì hữu ích vào lúc này ... thở dài, tốt thôi.

OK, hãy kiểm tra xem lớp shunt này có làm tốt không. Tạo một lớp tệp phẳng sẽ duy trì sản phẩm của bạn trong các tệp. Bây giờ lớp mới này đi đâu trong thiết kế này?

Chà, nó sẽ có thể đi đến nơi DB. Sau tất cả, chúng tôi không cần DB nữa vì chúng tôi đang sử dụng các tệp phẳng. Nhưng điều này cũng được cho là không cần kho lưu trữ.

Xem xét, có thể kho lưu trữ là một chi tiết thực hiện. Sau tất cả, tôi có thể nói chuyện với DB mà không cần sử dụng mẫu kho lưu trữ.

Front end <--> API Service -> Service -> Repository -> DB

Front end <--> API Service -> Service -> Repository -> Files

Front end <--> API Service -> Service -> Persistence -> DB

Front end <--> API Service -> Service -> Persistence -> Files

Nếu bạn có thể làm cho tất cả hoạt động mà không cần chạm vào Dịch vụ, bạn có mã linh hoạt.

Nhưng đừng hiểu ý tôi. Viết nó và xem những gì xảy ra. Mã duy nhất tôi tin là linh hoạt là mã uốn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.