คลาส RxJava Flowable ถูกต้องตามกฎหมายสามารถมี 460 วิธีได้หรือไม่?


14

ฉันเพิ่งเริ่มต้นกับRxJavaการใช้ReactiveXของ Java (หรือที่เรียกว่าRxและReactive Extensions ) สิ่งที่ทำให้ฉันหลงไหลจริงๆคือขนาดที่ใหญ่ของคลาสFlowableของ RxJava : มันมี 460 วิธี!

เพื่อความเป็นธรรม:

  • มีวิธีการมากมายที่มากเกินไปซึ่งกระแทกจำนวนวิธีทั้งหมดอย่างมีนัยสำคัญ

  • บางทีคลาสนี้ควรจะถูกทำลาย แต่ความรู้และความเข้าใจของฉันเกี่ยวกับ RxJava มี จำกัด มาก คนที่สร้าง RxJava นั้นฉลาดมากและพวกเขาสามารถเสนอข้อโต้แย้งที่ถูกต้องในการเลือกสร้างFlowableด้วยวิธีการมากมาย

ในทางกลับกัน:

  • RxJava เป็นการใช้งาน Java ของส่วนขยายรีแอกทีฟของMicrosoftและนั่นไม่ได้มีคลาสFlowableดังนั้นนี่ไม่ใช่กรณีของการย้ายคลาสที่มีอยู่แบบสุ่มและนำไปใช้ใน Java

  • [ อัปเดต:จุดก่อนหน้าในตัวเอียงไม่ถูกต้องตามจริง: คลาสObservableของ Microsoft ซึ่งมีมากกว่า 400 วิธีใช้เป็นพื้นฐานสำหรับคลาสObservableของ RxJava และFlowableนั้นคล้ายกับObservableแต่จัดการ backpressure สำหรับข้อมูลจำนวนมาก ดังนั้นทีม RxJava จึงย้ายคลาสที่มีอยู่ โพสต์นี้น่าจะท้าทายการออกแบบเดิมของคลาสObservableโดย Microsoft มากกว่าคลาสFlowableของ RxJava ]

  • RxJava อายุน้อยกว่า 3 ปีดังนั้นนี่ไม่ใช่ตัวอย่างของโค้ดที่ออกแบบมาผิดพลาดเนื่องจากขาดความรู้เกี่ยวกับหลักการออกแบบคลาส( SOLID ) ที่ดี(เช่นกรณีที่มี Java รุ่นแรก ๆ )

สำหรับชั้นเรียนขนาดใหญ่ที่สุดเท่าที่Flowableการออกแบบของมันดูเหมือนจะผิดไป แต่อาจจะไม่ใช่ คำตอบเดียวสำหรับคำถาม SE นี้การ จำกัด จำนวนวิธีการเรียนคืออะไร แนะนำว่าคำตอบคือ " มีหลายวิธีเท่าที่คุณต้องการ "

เห็นได้ชัดว่ามีบางคลาสที่ต้องใช้วิธีการที่ถูกต้องตามกฎหมายเพื่อรองรับพวกเขาโดยไม่คำนึงถึงภาษาเพราะพวกเขาไม่ได้แบ่งย่อยอะไรเป็นเรื่องเล็กและมีจำนวนคุณลักษณะและคุณสมบัติที่พอใช้ ตัวอย่างเช่น: สตริง, สี, เซลล์สเปรดชีต, ชุดผลลัพธ์ฐานข้อมูลและคำขอ HTTP อาจมีวิธีการไม่กี่โหลสำหรับชั้นเรียนเพื่อเป็นตัวแทนของสิ่งเหล่านั้นดูเหมือนจะไม่มีเหตุผล

แต่Flowableต้องการวิธีการ 460 อย่างแท้จริงหรือว่ามีขนาดใหญ่จนเป็นตัวอย่างของการออกแบบที่ไม่ดี

[เพื่อความชัดเจน: คำถามนี้เกี่ยวข้องกับคลาสFlowableของ RxJava โดยเฉพาะมากกว่าวัตถุของพระเจ้าโดยทั่วไป]



1
@gnat เกี่ยวข้องกันดีมาก แต่ก็ไม่ซ้ำกัน คำถามนั้นเป็นคำถามทั่วไปและคำถามของฉันเกี่ยวข้องกับคลาสFlowableของ RxJava โดยเฉพาะ
skomisa

@skomisa จากนั้นแก้ไขชื่อให้เหมาะกับคำถามของคุณ
ร่าเริง

@Euphoric Point ถ่ายไว้
skomisa

1
คำถามนี้น่าสนใจมากและก่อตั้งขึ้น อย่างไรก็ตามฉันขอแนะนำให้ใส่รหัสใหม่เล็กน้อยเพื่อปรับใช้สไตล์ที่เป็นอัตนัยน้อยลง (อาจเป็นเพราะช็อตเริ่มต้น ;-))
Christophe

คำตอบ:


14

TL; DL

การขาดคุณสมบัติด้านภาษาของ Java เมื่อเทียบกับ C # รวมถึงข้อควรระวังในการค้นพบทำให้เราใส่โอเปอเรเตอร์และสื่อกลางเข้าในคลาสขนาดใหญ่

ออกแบบ

Rx.NET ดั้งเดิมได้รับการพัฒนาใน C # 3.0 ซึ่งมีคุณสมบัติที่สำคัญสองประการ: วิธีการขยายและคลาสบางส่วน อดีตให้คุณกำหนดวิธีการอินสแตนซ์ในประเภทอื่นซึ่งดูเหมือนจะเป็นส่วนหนึ่งของประเภทเป้าหมายนั้นในขณะที่บางส่วนชั้นเรียนช่วยให้คุณสามารถแยกชั้นเรียนขนาดใหญ่เป็นหลายไฟล์

คุณสมบัติเหล่านี้ไม่ได้มีอยู่ใน Java ดังนั้นเราต้องหาวิธีที่จะให้ RxJava ใช้งานได้สะดวกพอ

มีตัวดำเนินการสองชนิดใน RxJava: คล้ายแหล่งที่มาที่แสดงโดยวิธีการโรงงานแบบคงที่และแบบกลางที่แสดงโดยวิธีการอินสแตนซ์ อดีตสามารถอาศัยอยู่ในชั้นเรียนใด ๆ และทำให้พวกเขาสามารถได้รับการกระจายไปตามชั้นยูทิลิตี้หลาย หลังจำเป็นต้องใช้อินสแตนซ์สำหรับการทำงาน ในแนวคิดเหล่านี้ทั้งหมดสามารถแสดงผ่านวิธีคงที่กับ upstream เป็นพารามิเตอร์แรก

อย่างไรก็ตามในทางปฏิบัติการมีคลาสเริ่มต้นหลายรายการทำให้การค้นหาคุณลักษณะโดยผู้ใช้ใหม่ไม่สะดวก (จำไว้ว่า RxJava ต้องนำแนวคิดใหม่และกระบวนทัศน์การเขียนโปรแกรมมาสู่ Java) เช่นเดียวกับการใช้ตัวดำเนินการระดับกลางเหล่านั้นค่อนข้างฝันร้าย ดังนั้นทีมดั้งเดิมจึงมาพร้อมกับการออกแบบที่เรียกว่า API ได้อย่างคล่องแคล่ว: ชั้นหนึ่งที่มีวิธีการคงที่และอินสแตนซ์ทั้งหมดและเป็นตัวแทนแหล่งที่มาหรือขั้นตอนการประมวลผลทั้งหมดด้วยตัวเอง

เนื่องจากข้อผิดพลาดระดับเฟิร์สคลาส, การสนับสนุนการทำงานพร้อมกันและลักษณะการทำงานหนึ่งสามารถเกิดขึ้นกับแหล่งที่มาและการเปลี่ยนแปลงทุกประเภทเกี่ยวกับการไหลของปฏิกิริยา เมื่อห้องสมุด (และแนวคิด) วิวัฒนาการมาตั้งแต่สมัยของ Rx.NET ผู้ประกอบการมาตรฐานมากขึ้นและมากขึ้นซึ่งโดยธรรมชาติจะเพิ่มจำนวนวิธีการ สิ่งนี้นำไปสู่การร้องเรียนปกติสองข้อ:

  • ทำไมมีวิธีการมากมาย?
  • ทำไมไม่มีวิธี X ที่แก้ปัญหาเฉพาะของฉันได้?

การเขียนโอเปอเรเตอร์แบบปฏิกิริยาเป็นงานที่ยากไม่กี่คนที่เชี่ยวชาญในช่วงหลายปี; ผู้ใช้ห้องสมุดทั่วไปส่วนใหญ่ไม่สามารถสร้างโอเปอเรเตอร์ได้ด้วยตนเอง ซึ่งหมายความว่าเราเพิ่มผู้ประกอบการเพิ่มเติมในชุดมาตรฐานเป็นครั้งคราว ในทางตรงกันข้ามเราได้ปฏิเสธผู้ให้บริการหลายรายเนื่องจากมีความเฉพาะเจาะจงมากเกินไปหรือเพียงแค่ความสะดวกสบายที่ไม่สามารถดึงน้ำหนักของตัวเองได้

ฉันจะบอกว่าการออกแบบของ RxJava เติบโตขึ้นอย่างเป็นธรรมชาติและไม่ได้เป็นไปตามหลักการออกแบบบางอย่างเช่น SOLID ส่วนใหญ่ขับเคลื่อนด้วยการใช้งานและความรู้สึกของ API ที่คล่องแคล่ว

ความสัมพันธ์อื่น ๆ กับ Rx.NET

ฉันเข้าร่วมการพัฒนา RxJava ในปลายปี 2556 เท่าที่ฉันสามารถบอกได้รุ่นเริ่มต้น 0.x ส่วนใหญ่เป็นการปรับใช้กล่องดำโดยที่ชื่อและลายเซ็นต์ของObservableผู้ประกอบการRx.NET รวมถึงการตัดสินใจทางสถาปัตยกรรมบางประการ สิ่งนี้เกี่ยวข้องกับผู้ให้บริการ Rx.NET ประมาณ 20% ปัญหาหลักที่ตามมาคือความละเอียดของภาษาและความแตกต่างของแพลตฟอร์มระหว่าง C # และ Java ด้วยความพยายามอย่างยิ่งยวดเราพยายามที่จะติดตั้งตัวดำเนินการจำนวนมากโดยไม่ต้องดูซอร์สโค้ดของ Rx.NET และเราจะทำการย้ายสิ่งที่ซับซ้อนมากขึ้น

ในแง่นี้จนถึง RxJava 0.19 เราObservableมีวิธีเทียบเท่ากับ Rx.NET IObservableและObservableวิธีการขยายร่วม อย่างไรก็ตามปัญหา backpressure ที่เรียกว่าปรากฏขึ้นและ RxJava 0.20 เริ่มที่จะแตกต่างจาก Rx.NET ในโปรโตคอลและระดับสถาปัตยกรรม ผู้ให้บริการที่มีอยู่ได้ขยายออกไปหลายคนเริ่มตระหนักถึงความกดดันและเราได้แนะนำรูปแบบใหม่: SingleและCompletableในยุค 1.x ซึ่งยังไม่มีคู่หูใน Rx.NET ณ ขณะนี้

Backpressure-awareness ทำให้สิ่งต่าง ๆ มีความซับซ้อนและ 1.x Observableได้รับมันในภายหลัง เราสาบานว่าจะจงรักภักดีต่อความเข้ากันได้ของไบนารีดังนั้นการเปลี่ยนโปรโตคอลและ API ส่วนใหญ่จึงเป็นไปไม่ได้

มีปัญหาอีกอย่างหนึ่งเกี่ยวกับสถาปัตยกรรมของ Rx.NET: การยกเลิกแบบซิงโครนัสไม่สามารถทำได้เนื่องจากการทำเช่นนั้นจำเป็นDisposableต้องส่งคืนก่อนที่โอเปอเรเตอร์จะเริ่มดำเนินการ อย่างไรก็ตามแหล่งข้อมูลเช่นRangeเคยกระตือรือร้นและจะไม่กลับจนกว่าจะเสร็จสิ้น ปัญหานี้สามารถแก้ไขได้โดยการฉีดDisposableเข้าไปในแทนที่จะกลับจากObserversubscribe()

RxJava 2.x ได้รับการออกแบบใหม่และนำไปใช้ใหม่ตั้งแต่เริ่มต้นตามเส้นเหล่านี้ เรามีแยกประเภท backpressure ทราบซึ่งมีชุดเดียวกันของผู้ประกอบการเป็นFlowable ไม่สนับสนุน backpressure และค่อนข้างเทียบเท่ากับ Rx.NET ภายในทุกประเภทปฏิกิริยาตอบสนองต่อการจัดการการยกเลิกให้กับผู้บริโภคของพวกเขาช่วยให้การยกเลิกการซิงโครนัสทำงานได้อย่างมีประสิทธิภาพObservableObservableObservable


10

ในขณะที่ฉันยอมรับว่าฉันไม่คุ้นเคยกับห้องสมุดฉันลองดูคำถามในชั้นเรียนเกี่ยวกับFlowableและดูเหมือนว่ามันจะทำหน้าที่เหมือนเป็นศูนย์กลาง กล่าวอีกนัยหนึ่งมันเป็นคลาสที่หมายถึงการตรวจสอบการป้อนข้อมูลและกระจายสายตามในโครงการ

ชั้นเรียนนี้จะไม่ถือว่าเป็นวัตถุของพระเจ้าเพราะวัตถุของพระเจ้าเป็นสิ่งหนึ่งที่พยายามทำทุกสิ่ง สิ่งนี้ทำในแง่ของตรรกะน้อยมาก ในแง่ของความรับผิดชอบเดี่ยวงานเดียวของชั้นเรียนอาจกล่าวได้ว่าเป็นการมอบหมายงานทั่วทั้งห้องสมุด

ดังนั้นคลาสดังกล่าวจะต้องมีวิธีการสำหรับงานทุกอย่างที่เป็นไปได้ที่คุณต้องการของFlowableคลาสในบริบทนี้ คุณเห็นรูปแบบเดียวกันกับห้องสมุด jQuery ใน javascript ซึ่งตัวแปร$มีฟังก์ชั่นและตัวแปรทั้งหมดที่จำเป็นสำหรับการโทรบนห้องสมุดแม้ว่าในกรณีของ jQuery รหัสไม่ได้รับการมอบหมายเพียงอย่างเดียว แต่ยังเป็นตรรกะที่ดี ทำงานภายใน

ฉันคิดว่าคุณควรระมัดระวังในการสร้างคลาสเช่นนี้ แต่มันมีสถานที่ตราบใดที่ผู้พัฒนาจำได้ว่ามันเป็นเพียงฮับและดังนั้นจึงไม่แปลงเป็นวัตถุเทพเจ้าช้า


2
ขออภัยในการยกเลิกการยอมรับคำตอบของคุณซึ่งทั้งสองเป็นประโยชน์และให้ความกระจ่าง แต่คำตอบที่ตามมาของ akarnokd นั้นมาจากใครบางคนในทีม RxJava!
skomisa

@skomisa ฉันจะหวังอะไรอีกถ้ามันเป็นคำถามของฉันเอง! ไม่มีการกระทำผิดกฎหมาย! :)
Neil

7

.NET ของ RX เพื่อเทียบเท่าFlowableคือสังเกต นอกจากนี้ยังมีทั้งหมดของวิธีการเหล่านั้น แต่พวกเขาจะคงที่และใช้งานเป็นวิธีการขยาย จุดหลักของ RX คือองค์ประกอบเขียนโดยใช้อินเตอร์เฟซได้อย่างคล่องแคล่ว

แต่สำหรับ Java ที่จะมีส่วนต่อประสานที่คล่องแคล่วมันต้องการ metods เหล่านั้นเป็นวิธีการแบบอินสแตนซ์เนื่องจากวิธีการแบบคงที่จะไม่เขียนอย่างดีและไม่มีวิธีการขยายเพื่อให้วิธีการแบบคงที่คอมโพสิต ดังนั้นในทางปฏิบัติวิธีการทั้งหมดนั้นสามารถสร้างวิธีการแบบคงที่ตราบใดที่คุณไม่ต้องใช้ไวยากรณ์ส่วนต่อประสานที่คล่องแคล่ว


3
แนวคิดส่วนต่อประสานที่ใช้งานง่ายคือ IMHO ซึ่งเป็นวิธีแก้ปัญหาข้อ จำกัด ด้านภาษา อย่างมีประสิทธิภาพคุณกำลังสร้างภาษาโดยใช้คลาสที่ด้านบนของ Java หากคุณคิดถึงจำนวนฟีเจอร์ในภาษาการเขียนโปรแกรมอย่างง่ายที่มีและไม่นับรวมตัวแปรที่มากเกินไปมันจะค่อนข้างง่ายที่จะเห็นว่าคุณจะจบลงด้วยวิธีการมากมาย คุณสมบัติการทำงานของ Java 8 สามารถแก้ไขปัญหามากมายที่นำไปสู่การออกแบบและภาษาร่วมสมัยเช่น Kotlin กำลังจะได้รับประโยชน์ในรูปแบบเดียวกันโดยไม่ต้องใช้วิธีการผูกมัด
JimmyJames

ขอบคุณที่โพสต์ของคุณฉันขุดลึกลงไปและดูเหมือนว่า RX's Observable ของ. NET คือ≈ถึง RxJava's Observable ดังนั้นคำถามของฉันจึงไม่ถูกต้อง ฉันได้อัปเดต OP แล้ว นอกจากนี้ Flowable R ของ RxJava (Observable + สองสามวิธีพิเศษสำหรับขนานและการจัดการความดันกลับ)
skomisa

@skomisa Java's Observable ก็มีหลายร้อยวิธี ดังนั้นคุณสามารถเปรียบเทียบทั้งสอง แต่ความแตกต่างที่สำคัญคือ Observable ของ. NET นั้นคงที่และวิธีการทั้งหมดนั้นคงที่ ในขณะที่ Java นั้นไม่ใช่ และนั่นคือความแตกต่างอย่างมาก แต่ในทางปฏิบัติพวกเขาปฏิบัติตนเหมือนกัน
ร่าเริง
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.