Lớp RxJava Flowable hợp pháp có thể có 460 phương thức không?


14

Tôi mới bắt đầu với RxJava , triển khai ReactiveX của Java (còn được gọi là RxReactive Extension ). Cái gì đó thực sự xảy ra với tôi là kích thước khổng lồ của RxJava của Bê tông lỏng lớp : nó có 460 phương pháp!

Để có sự công bằng:

  • Có rất nhiều phương thức bị quá tải, làm giảm đáng kể tổng số phương thức.

  • Có lẽ lớp học này nên được chia ra, nhưng kiến ​​thức và hiểu biết của tôi về RxJava rất hạn chế. Những người đã tạo ra RxJava chắc chắn rất thông minh và có lẽ họ có thể đưa ra các đối số hợp lệ để chọn tạo Flowable với rất nhiều phương thức.

Mặt khác:

  • RxJava là triển khai Java của Phần mở rộng phản ứng của Microsoft và thậm chí không có lớp Flowable , vì vậy đây không phải là trường hợp chuyển một cách mù quáng một lớp hiện có và triển khai nó trong Java.

  • [ Cập nhật: Vấn đề trước in nghiêng là không chính xác: của Microsoft Quan sát lớp học, trong đó có hơn 400 phương pháp, đã được sử dụng làm cơ sở cho RxJava của Quan sát lớp học, và Bê tông lỏng tương tự như Quan sát nhưng xử lý Backpressure cho khối lượng lớn dữ liệu. Vì vậy, nhóm RxJava đã chuyển một lớp hiện có. Bài này nên đã thách thức thiết kế ban đầu của Quan sát lớp của Microsoft chứ không phải RxJava của Bê tông lỏng lớp.]

  • RxJava chỉ mới hơn 3 tuổi một chút, vì vậy đây không phải là một ví dụ về mã được thiết kế sai do thiếu kiến ​​thức về các nguyên tắc thiết kế lớp tốt ( RẮN ) (như trường hợp phát hành sớm của Java).

Đối với một lớp lớn như Flowable, thiết kế của nó có vẻ sai, nhưng có lẽ không; một câu trả lời cho câu hỏi SE này Giới hạn số lượng của một phương thức lớp là gì? đề nghị rằng câu trả lời là " Có nhiều phương pháp bạn cần ".

Rõ ràng có một số lớp hợp pháp cần một số phương pháp hợp lý để hỗ trợ chúng bất kể ngôn ngữ, bởi vì chúng không dễ dàng phân tách thành bất cứ thứ gì nhỏ hơn và chúng có số lượng đặc điểm và thuộc tính hợp lý. Ví dụ: chuỗi, màu sắc, ô bảng tính, tập kết quả cơ sở dữ liệu và yêu cầu HTTP. Có lẽ có vài chục phương thức để các lớp đại diện cho những thứ đó dường như không hợp lý.

Nhưng Flowable có thực sự cần 460 phương thức hay nó quá lớn đến nỗi nó nhất thiết phải là một ví dụ về thiết kế lớp xấu?

[Để được rõ ràng: Câu hỏi này đặc biệt liên quan đến RxJava của Bê tông lỏng lớp chứ không phải là đối tượng Thiên Chúa nói chung.]



1
@gnat Chắc chắn có liên quan, nhưng nó không phải là một bản sao. Câu hỏi đó là chung chung, và câu hỏi của tôi đặc biệt liên quan đến RxJava của Bê tông lỏng lớp.
skomisa

@skomisa Sau đó sửa tiêu đề cho phù hợp với câu hỏi của bạn.
Euphoric

@Euphoric Điểm lấy.
skomisa

1
Câu hỏi này rất thú vị và được thành lập. Tuy nhiên, tôi muốn đề nghị để xây dựng lại và nhẹ để áp dụng một phong cách ít chủ quan (có thể là do cú sốc ban đầu ;-))
Christophe

Câu trả lời:


14

TL; DL

Việc thiếu các tính năng ngôn ngữ của Java so với C # cũng như các cân nhắc về khả năng khám phá đã khiến chúng tôi đưa các toán tử nguồn và trung gian vào các lớp lớn.

Thiết kế

Rx.NET ban đầu được phát triển trong C # 3.0 có hai tính năng quan trọng: phương thức mở rộng và lớp một phần. Cái trước cho phép bạn định nghĩa các phương thức cá thể trên các loại khác mà sau đó dường như là một phần của loại mục tiêu đó trong khi các lớp một phần cho phép bạn chia các lớp lớn thành nhiều tệp.

Cả hai tính năng này đều không có hoặc có trong Java, do đó, chúng tôi phải tìm cách để RxJava có thể sử dụng đủ tiện lợi.

Có hai loại toán tử trong RxJava: giống như nguồn được biểu thị bằng các phương thức tĩnh của nhà máy và giống như trung gian được biểu diễn bằng các phương thức thể hiện. Cái trước có thể sống trong bất kỳ lớp nào và do đó chúng có thể được phân phối dọc theo nhiều lớp tiện ích. Cái sau đòi hỏi một thể hiện để được làm việc trên. Về khái niệm, tất cả những thứ này có thể được thể hiện thông qua các phương thức tĩnh với ngược dòng là tham số đầu tiên.

Tuy nhiên, trên thực tế, việc có nhiều lớp nhập khiến người dùng mới phát hiện ra tính năng bất tiện (hãy nhớ rằng, RxJava phải đưa một khái niệm mới và mô hình lập trình vào Java) cũng như việc sử dụng các toán tử trung gian đó phần nào là một cơn ác mộng. Do đó, nhóm ban đầu đã đưa ra cái gọi là thiết kế API trôi chảy: một lớp chứa tất cả các phương thức tĩnh và cá thể và tự thể hiện một giai đoạn nguồn hoặc xử lý.

Do tính chất hạng nhất của lỗi, hỗ trợ đồng thời và bản chất chức năng, người ta có thể đưa ra tất cả các loại nguồn và biến đổi liên quan đến dòng phản ứng. Khi thư viện (và khái niệm) phát triển kể từ thời Rx.NET, ngày càng có nhiều toán tử tiêu chuẩn được thêm vào, điều này về bản chất làm tăng số lượng phương thức. Điều này dẫn đến hai khiếu nại thông thường:

  • Tại sao có nhiều phương pháp?
  • Tại sao không có phương pháp X giải quyết vấn đề rất đặc biệt của tôi?

Viết toán tử phản ứng là nhiệm vụ khó khăn không nhiều người thành thạo trong những năm qua; hầu hết người dùng thư viện điển hình không thể tự tạo toán tử (và thường thì họ không thực sự cần thiết để thử). Điều này có nghĩa là chúng ta, theo thời gian, thêm các toán tử tiếp theo vào bộ tiêu chuẩn. Ngược lại, chúng tôi đã từ chối nhiều nhà khai thác hơn do quá cụ thể hoặc đơn giản là sự tiện lợi không thể tự nâng trọng lượng của nó.

Tôi muốn nói rằng thiết kế của RxJava đã phát triển một cách hữu cơ và không thực sự tuân theo các nguyên tắc thiết kế nhất định như RẮN. Nó chủ yếu được điều khiển bởi việc sử dụng và cảm nhận về API thông thạo của nó.

Các mối quan hệ khác với Rx.NET

Tôi đã tham gia phát triển RxJava vào cuối năm 2013. Theo như tôi có thể nói, các phiên bản 0.x ban đầu phần lớn là sự tái hiện hộp đen trong đó tên và chữ ký của các Observablenhà khai thác Rx.NET cũng như một vài quyết định kiến ​​trúc được sử dụng lại. Điều này liên quan đến khoảng 20% ​​các nhà khai thác Rx.NET. Khó khăn chính trước đó là độ phân giải của sự khác biệt về ngôn ngữ và nền tảng giữa C # và Java. Với nỗ lực rất lớn, chúng tôi đã quản lý để triển khai nhiều toán tử mà không cần nhìn vào mã nguồn của Rx.NET và chúng tôi đã chuyển các mã phức tạp hơn.

Theo nghĩa này, cho đến RxJava 0.19, chúng tôi Observabletương đương với Rx.NET IObservablevà các Observablephương thức mở rộng đồng hành của nó . Tuy nhiên, vấn đề được gọi là áp suất ngược đã xuất hiện và RxJava 0.20 bắt đầu phân kỳ khỏi Rx.NET ở cấp độ giao thức và kiến ​​trúc. Các toán tử có sẵn đã được mở rộng, nhiều người đã biết áp lực và chúng tôi đã giới thiệu các loại mới: SingleCompletabletrong kỷ nguyên 1.x, không có đối tác trong Rx.NET như bây giờ.

Nhận thức về áp lực làm phức tạp mọi thứ một cách đáng kể và 1.x Observableđã nhận nó như một suy nghĩ lại. Chúng tôi thề trung thành với khả năng tương thích nhị phân nên việc thay đổi giao thức và API hầu như không thể.

Có một vấn đề khác với kiến ​​trúc của Rx.NET: không thể hủy bỏ đồng bộ vì để làm điều đó, người ta cần Disposablephải trả lại trước khi toán tử bắt đầu thực thi. Tuy nhiên, các nguồn như Rangeháo hức và không trở lại cho đến khi họ hoàn thành. Vấn đề này có thể được giải quyết bằng cách tiêm một Disposablecái Observerthay vì trả lại từ đó subscribe().

RxJava 2.x được thiết kế lại và thực hiện lại từ đầu dọc theo các dòng này. Chúng tôi có một loại nhận biết áp lực riêng biệt, Flowablecung cấp cùng một bộ toán tử như Observable. Observablekhông hỗ trợ backpressure và có phần tương đương với Rx.NET Observable. Trong nội bộ, tất cả các loại phản ứng tiêm xử lý hủy bỏ của họ cho người tiêu dùng của họ, cho phép hủy bỏ đồng bộ để làm việc hiệu quả.


10

Trong khi tôi thừa nhận tôi không quen thuộc với thư viện, tôi đã xem xét lớp Flowable đang được đề cập và có vẻ như nó hoạt động giống như một trung tâm sắp xếp. Nói cách khác, đây là một lớp có nghĩa là để xác nhận đầu vào và phân phối các cuộc gọi phù hợp trong dự án.

Do đó, lớp này sẽ không thực sự được coi là một đối tượng của Thiên Chúa vì một đối tượng của Thiên Chúa là một đối tượng cố gắng làm mọi thứ. Điều này rất ít về mặt logic. Về trách nhiệm đơn lẻ, công việc duy nhất của lớp có thể nói là ủy thác công việc trong toàn thư viện.

Vì vậy, một cách tự nhiên một lớp như vậy sẽ yêu cầu một phương thức cho mọi nhiệm vụ có thể bạn yêu cầu của một Flowablelớp trong ngữ cảnh này. Bạn thấy cùng một kiểu mẫu với thư viện jQuery trong javascript, trong đó biến $có tất cả các hàm và biến cần thiết để thực hiện các cuộc gọi trên thư viện, mặc dù trong trường hợp của jQuery, mã không chỉ được ủy thác mà còn có một chút logic. được chạy trong.

Tôi nghĩ bạn nên cẩn thận để tạo một lớp như thế này, nhưng nó có vị trí của nó miễn là nhà phát triển nhớ rằng nó chỉ là một trung tâm, và do đó không từ từ chuyển đổi thành một đối tượng thần.


2
Xin lỗi vì đã loại bỏ chấp nhận câu trả lời của bạn, điều này vừa hữu ích vừa giác ngộ, nhưng phản hồi sau đó của akarnokd là từ một người nào đó trong nhóm RxJava!
skomisa

@skomisa Tôi không thể hy vọng gì hơn nếu đó là câu hỏi của riêng tôi! Không có sự xúc phạm nào! :)
Neil

7

Tương đương với RX của .NET Flowablelà có thể quan sát được . Nó cũng có tất cả các phương thức đó, nhưng chúng là tĩnh và có thể sử dụng như các phương thức mở rộng . Điểm chính của RX là bố cục được viết bằng giao diện trôi chảy .

Nhưng để Java có giao diện lưu loát, nó cần các phương thức này là các phương thức cá thể, vì các phương thức tĩnh sẽ không kết hợp tốt và nó không có các phương thức mở rộng để làm cho các phương thức tĩnh có thể ghép được. Vì vậy, trong thực tế, tất cả các phương thức đó có thể được tạo thành các phương thức tĩnh, miễn là bạn không sử dụng cú pháp giao diện trôi chảy.


3
Khái niệm giao diện lưu loát là, IMHO, một giải pháp cho những hạn chế về ngôn ngữ. Thực tế, bạn đang xây dựng một ngôn ngữ bằng cách sử dụng một lớp trên đầu Java. Nếu bạn nghĩ về việc có bao nhiêu tính năng trong một ngôn ngữ lập trình đơn giản và không tính tất cả các biến thể bị quá tải, thì việc xem bạn kết thúc với nhiều phương thức này sẽ trở nên khá dễ dàng. Các tính năng chức năng của Java 8 có thể giải quyết rất nhiều vấn đề dẫn đến kiểu thiết kế này và các ngôn ngữ đương đại như Kotlin đang di chuyển để có thể nhận được cùng loại lợi ích mà không cần phải sử dụng phương thức.
JimmyJames

Nhờ bài đăng của bạn, tôi đã đào sâu hơn và có vẻ như Observable của .NET là ≈ đối với RxJava's Observable, do đó, tiền đề cho câu hỏi của tôi là không chính xác. Tôi đã cập nhật OP cho phù hợp. Ngoài ra, RxJava 'Flowable (Có thể quan sát + một vài phương pháp bổ sung để xử lý song song và xử lý áp lực).
skomisa

@skomisa Java's Observable cũng có hàng trăm phương thức. Vì vậy, bạn có thể so sánh hai. Nhưng sự khác biệt chính là .NET's Observable là tĩnh và tất cả các phương thức đều tĩnh. Trong khi Java thì không. Và đó là sự khác biệt rất lớn. Nhưng trong thực tế, họ hành xử giống nhau.
Euphoric
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.