Может ли класс RxJava Flowable законно иметь 460 методов?

14

Я только начинаю с RxJava , Java-реализации ReactiveX (также известной как Rx и Reactive Extensions ). То , что действительно поразило меня массовый размер RxJava в текучий классе : он имеет 460 методы!

По честному:

  • Есть много методов, которые перегружены, что значительно увеличивает общее количество методов.

  • Возможно, этот класс следует разбить, но мои знания и понимание RxJava очень ограничены. Люди, которые создали RxJava, безусловно, очень умны, и они, вероятно, могут предложить веские аргументы для выбора создания Flowable с таким количеством методов.

С другой стороны:

  • RxJava - это Java-реализация Microsoft Reactive Extensions , которая даже не имеет класса Flowable , так что это не случай слепой портирования существующего класса и его реализации в Java.

  • [ Обновление: предыдущий пункт в курсиве фактически неверен: класс Observable от Microsoft , который имеет более 400 методов, использовался в качестве основы для класса Observable в RxJava , а Flowable аналогичен Observable, но обрабатывает противодавление для больших объемов данных. Таким образом, команда RxJava были портирование существующего класса. Этот пост должен был оспорить оригинальный дизайн наблюдаемого класса по Microsoft , а не RxJava в текучем классе.]

  • RxJava всего немногим более 3 лет, так что это не пример неправильного проектирования кода из-за недостатка знаний о хороших ( SOLID ) принципах проектирования классов (как это было в ранних выпусках Java).

Для такого большого класса, как Flowable, его дизайн кажется неправильным, но, возможно, нет; один ответ на этот вопрос SE Каково ограничение на количество методов класса? предположил, что ответ « есть столько методов, сколько вам нужно ».

Очевидно, что есть некоторые классы, которым на законных основаниях требуется достаточное количество методов для их поддержки независимо от языка, потому что они не разбиваются на что-то меньшее и имеют достаточное количество характеристик и атрибутов. Например: строки, цвета, ячейки электронной таблицы, наборы результатов базы данных и HTTP-запросы. Возможно, наличие нескольких десятков методов для классов, представляющих эти вещи, не кажется необоснованным.

Но действительно ли Flowable нужны 460 методов, или он настолько велик, что обязательно является примером плохого дизайна класса?

[Чтобы быть ясно: этот вопрос конкретно относится к RxJava в текучий класса , а не объекты Бога вообще.]

skomisa
источник
1
@gnat Ну, конечно, связано, но это не дубликат. Этот вопрос был общим, и мой вопрос конкретно относится к RxJava в текучий классе.
скомиса
@skomisa Затем исправьте заголовок, чтобы он соответствовал вашему вопросу.
Euphoric
@ Эйфорическая точка принята.
скомиса
1
Этот вопрос очень интересный и обоснованный. Тем не менее, я бы предложил немного перефразировать его, чтобы принять менее субъективный стиль (вероятно, из-за первоначального шока ;-))
Кристоф

Ответы:

14

TL; DL

Отсутствие языковых возможностей Java по сравнению с C #, а также соображения об открываемости заставили нас поместить исходные и промежуточные операторы в большие классы.

дизайн

Оригинальный Rx.NET был разработан в C # 3.0, который имеет две важные функции: методы расширения и частичные классы. Первый позволяет вам определять методы экземпляра для других типов, которые затем становятся частью этого целевого типа, тогда как частичные классы позволяют разбивать большие классы на несколько файлов.

Ни одна из этих функций не была и не присутствует в Java, поэтому нам пришлось искать способ сделать RxJava удобным для использования.

В RxJava есть два вида операторов: исходные, представленные статическими фабричными методами, и промежуточные, представленные экземплярами. Первые могут жить в любом классе, и, таким образом, они могут быть распределены по нескольким служебным классам. Последний требует, чтобы экземпляр работал. По идее, все это можно выразить статическими методами с восходящим потоком в качестве первого параметра.

На практике, однако, наличие нескольких классов входа делает обнаружение новых пользователей неудобным (помните, что RxJava должен был привнести новую концепцию и парадигму программирования в Java), а также использование этих промежуточных операторов в некотором смысле кошмар. Поэтому первоначальная команда разработала так называемый плавный дизайн API: один класс, который содержит все методы static и instance и представляет собой источник или этап обработки самостоятельно.

Из-за первоклассной природы ошибок, поддержки параллелизма и функциональной природы, можно придумать всевозможные источники и преобразования относительно реактивного потока. По мере развития библиотеки (и концепции) со времен Rx.NET все больше и больше стандартных операторов добавлялись, что по своей природе увеличивало количество методов. Это приводит к двум обычным жалобам:

  • Почему так много методов?
  • Почему нет метода X, который решает мою особую проблему?

Написание реактивных операторов - трудная задача, с которой не справились многие люди; большинство типичных пользователей библиотеки не могут сами создавать операторы (и зачастую им не обязательно пытаться это делать). Это означает, что мы время от времени добавляем дополнительные операторы в стандартный набор. Напротив, мы отказались от многих других операторов из-за того, что они слишком специфичны или просто из-за удобства, которое не может тянуть свой вес.

Я бы сказал, что дизайн RxJava развивался органически, а не в соответствии с определенными принципами проектирования, такими как SOLID. Это главным образом обусловлено использованием и ощущением его свободного API.

Другие отношения к Rx.NET

Я присоединился к разработке RxJava в конце 2013 года. Насколько я могу судить, начальные ранние версии 0.x были в основном переопределением черного ящика, в котором имена и подписи Observableоператоров Rx.NET, а также несколько архитектурных решений использовались повторно. В этом участвовало около 20% операторов Rx.NET. Тогда главной трудностью было разрешение языковых и платформенных различий между C # и Java. С огромными усилиями нам удалось реализовать множество операторов, не глядя на исходный код Rx.NET, и мы портировали более сложные.

В этом смысле, вплоть до RxJava 0.19, наш Observableбыл эквивалентен Rx.NET IObservableи его сопутствующим Observableметодам расширения. Однако появилась так называемая проблема противодавления, и RxJava 0.20 начал расходиться с Rx.NET на уровне протокола и архитектуры. Доступные операторы были расширены, многие стали реагировать на противодавление, и мы ввели новые типы: Singleи Completableв эпоху 1.x, у которых на данный момент нет аналогов в Rx.NET.

Осознание противодавления значительно усложняет ситуацию, и 1.x Observableполучает это в качестве запоздалой мысли. Мы поклялись в верности двоичной совместимости, поэтому изменение протокола и API в большинстве случаев было невозможно.

Была еще одна проблема с архитектурой Rx.NET: синхронная отмена невозможна, потому что для этого нужно Disposableвернуть ее, прежде чем оператор начнет выполнение. Тем не менее, источники, которые Rangeбыли готовы и не возвращаются, пока они не закончат. Эта проблема может быть решена путем введения Disposableв Observerвместо возвращения одного из subscribe().

RxJava 2.x был переработан и реализован с нуля по этим направлениям. У нас есть отдельный тип с поддержкой обратного давления, Flowableкоторый предлагает тот же набор операторов, что и Observable. Observableне поддерживает противодавление и в некоторой степени эквивалентно Rx.NET Observable. Внутренне все реактивные типы вводят свой дескриптор отмены своим потребителям, что позволяет эффективно работать синхронному аннулированию.

akarnokd
источник
10

Хотя я признаю, что не знаком с библиотекой, я взглянул на рассматриваемый класс Flowable, и кажется, что он действует как своего рода центр. Другими словами, это класс, предназначенный для проверки ввода и соответствующего распределения вызовов в проекте.

Следовательно, этот класс на самом деле не будет рассматриваться как объект Бога, так как объект Бога пытается сделать все. Это очень мало с точки зрения логики. С точки зрения единоличной ответственности, можно сказать, что единственной работой класса является делегирование работы по всей библиотеке.

Поэтому, естественно, что для такого класса потребуется метод для каждой возможной задачи, которую вам потребуется от Flowableкласса в этом контексте. Вы видите тот же тип шаблона с библиотекой jQuery в javascript, где переменная $имеет все функции и переменные, необходимые для выполнения вызовов библиотеки, хотя в случае с jQuery код не просто делегируется, но и обладает хорошей логикой работает внутри.

Я думаю, что вы должны быть осторожны, чтобы создать такой класс, но он имеет свое место, пока разработчик помнит, что это всего лишь концентратор, и, следовательно, не медленно превращается в объект бога.

Нил
источник
2
Извиняюсь за удаление вашего ответа, который был и полезен, и поучителен, но последующий ответ akarnokd был от кого-то из команды RxJava!
скомиса
@skomisa Я бы больше не надеялся, если бы это был мой собственный вопрос! Без обид! :)
Нил
7

Эквивалент RX для .NET Flowable- Observable . В нем также есть все эти методы, но они являются статическими и могут использоваться как методы расширения . Суть RX в том, что композиция написана с использованием свободного интерфейса .

Но для того, чтобы у Java был свободный интерфейс, эти методы должны быть методами экземпляра, так как статические методы не могли бы хорошо сочиняться, и у них нет методов расширения, чтобы сделать статические методы компонуемыми. Таким образом, на практике все эти методы могут быть сделаны статическими, если у вас все в порядке, не используя свободный синтаксис интерфейса.

Euphoric
источник
3
Свободная концепция интерфейса, IMHO, это обходной путь для языковых ограничений. По сути, вы создаете язык, используя класс поверх Java. Если вы думаете о том, сколько функций есть даже в простом языке программирования, и не учитываете все перегруженные варианты, становится довольно легко увидеть, как вы в конечном итоге получаете такое количество методов. Функциональные возможности Java 8 могут решить многие проблемы, которые приводят к такому типу проектирования, и современные языки, такие как Kotlin, стремятся получить те же преимущества без необходимости в цепочке методов.
JimmyJames
Благодаря вашему посту я вырыл глубже, и кажется, что .NET RX Observable предназначен для RxJava Observable, поэтому предпосылка моего вопроса была неверной. Я обновил ОП соответственно. Кроме того, RxJava Flowable - (Observable + несколько дополнительных методов для распараллеливания и обработки противодавления).
скомиса
@skomisa Java's Observable также имеет сотни методов. Таким образом, вы можете сравнить два. Но главное отличие состоит в том, что .NET Observable является статическим, а все методы статическими. Хотя Java нет. И это огромная разница. Но на практике они ведут себя одинаково.
Euphoric