Сколько из них слишком много в классе? [закрыто]

Я бы, вероятно, подумал, что это запах кода или даже анти-шаблон, чтобы иметь класс, который реализует 23 интерфейса. Если это действительно анти-шаблон, что бы вы назвали? Или это просто не соответствует принципу единой ответственности?

28 голосов | спросил Jonas Elfström 3 42011vEurope/Moscow11bEurope/MoscowThu, 03 Nov 2011 16:54:02 +0400 2011, 16:54:02

9 ответов


36

Королевская семья: они не делают ничего особенно сумасшедшего, но у них есть миллиард титулов и как-то связаны с большинством других членов королевской семьи.

ответил World Engineer 3 42011vEurope/Moscow11bEurope/MoscowThu, 03 Nov 2011 18:43:47 +0400 2011, 18:43:47
23

Я утверждаю, что этот анти-шаблон будет называться Jack of All Trades или, возможно, слишком много шляп.

ответил Mike Partridge 3 42011vEurope/Moscow11bEurope/MoscowThu, 03 Nov 2011 17:10:59 +0400 2011, 17:10:59
17

Если бы мне пришлось назвать это имя, я бы назвал его Hydra :

Hydra

  

В греческой мифологии Лернейская Гидра (греч. Λερναία Ὕδρα) была древним безымянным змеевидным хтоническим водяным зверем, с рептилийскими чертами (как его зовут), которое обладало многими головами - поэты упоминают больше голов, чем ваза - красавицы могли рисовать, и для каждой отрезанной головы он вырос еще на два - и ядовитое дыхание настолько опасно, что даже ее следы были смертельными.

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

Один из ранних признаков надвигающейся гибели из-за «Гидры» - это частое отбрасывание одного интерфейса другому, без большой проверки здравомыслия и часто до цели, которая не имеет смысла, как в:

public void CreateWidget(IPartLocator locator, int widgetTypeId)
{
    var partsNeeded = locator.GetPartsForWidget(widgetTypeId);
    return ((IAssembler)locator).BuildWidget(partsNeeded);
}

Очевидно, что, когда из контекста видно, что в этом коде есть что-то подозрительное, но вероятность того, что это происходит, растет с увеличением «головок», когда объект растет, потому что разработчики интуитивно знают , что они " всегда имея дело с тем же существом.

Удачи ever выполнять любое обслуживание объекта, который реализует 23 интерфейса. Шансы вы not , вызывающие побочный ущерб в процессе, невелики.

ответил Aaronaught 10 42011vEurope/Moscow11bEurope/MoscowThu, 10 Nov 2011 08:54:03 +0400 2011, 08:54:03
16

На ум приходит объект Бога ; один объект, который знает, как делать ВСЁ. Это связано с низкой приверженностью требованиям «сплоченности» двух основных методологий проектирования; если у вас есть объект с 23 интерфейсами, у вас есть объект, который знает, как его 23 пользователям, и эти 23 разных вещи, скорее всего, не соответствуют одной задаче или области системы.

В SOLID, в то время как создатель этого объекта, очевидно, попытался следовать Принципу разделения сегментов, они нарушили прежнее правило; Единый принцип ответственности. Есть причина, что это «ТВЕРДОЕ»; S всегда приходит первым, думая о дизайне, и все остальные правила следуют.

В GRASP создатель такого класса пренебрег правилом «High Cohesion»; GRASP, в отличие от SOLID, учит, что объект не должен обладать единой ответственностью, но в лучшем случае он должен иметь две или три очень тесно связанные обязанности.

ответил KeithS 3 42011vEurope/Moscow11bEurope/MoscowThu, 03 Nov 2011 18:17:53 +0400 2011, 18:17:53
8

23 Это просто номер! В наиболее вероятном сценарии он достаточно высок, чтобы сигнализировать. Однако, если мы спросим, ​​каково максимальное количество методов /интерфейсов, прежде чем он сможет получить тег, который будет вызываться как «анти-шаблон»? Это 5 или 10 или 25? Вы понимаете, что число действительно не является ответом, потому что, если 10 хорош, 11 также может быть - и после этого любое целое число после этого.

Реальный вопрос о сложности. И мы должны отметить, что длительный код, количество методов или большой размер класса с помощью любых мер на самом деле NOT определение сложности. Да, чем больше и больше код (большее количество методов), тем сложнее читать и понимать нового новичка. Он также обрабатывает потенциально разнообразную функциональность, большое количество исключений и довольно развитые алгоритмы для различных сценариев. Это не значит, что оно сложное - его трудно усвоить.

С другой стороны, относительно небольшой размерный код, который можно надеяться зачитать за несколько часов подряд, может быть сложным. Вот когда я думаю, что код (излишне) сложный.

Каждый кусочек мудрости объектно-ориентированного дизайна может быть приведен здесь, чтобы определить «сложный», но я бы ограничил здесь, чтобы показать, когда «очень много методов» является показателем сложности.

  1. Взаимное знание. (соединение a.k.a) Много раз, когда вещи записываются как классы, мы все думаем, что это «хороший» объектно-ориентированный код. Но предположение о другом классе существенно разрушает реальную необходимую инкапсуляцию. Когда у вас есть методы, которые «утешают» глубинные детали о внутреннем состоянии алгоритмов, - и приложение построено с ключевым допущением о внутреннем состоянии обслуживающего класса.

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

  3. Слишком много ролей Когда класс продолжает добавлять боковые функции и продолжает расширяться по мере того, как им нравится, только чтобы знать, что класс действительно является теперь двумя классами. Удивительно, но все они начинаются с подлинных требований, и для этого не существует другого класса. Рассмотрим это, есть класс Transaction, в котором указаны детали транзакции. Выглядит хорошо, теперь кому-то требуется преобразование формата в «время транзакции» (между UTC и т. Д.), А позже люди добавляют правила, чтобы проверить, были ли определенные вещи на определенные даты, чтобы проверить недействительные транзакции. - Я не буду писать всю историю, но в конце концов, класс транзакций строит весь календар с этим, а затем люди начинают использовать только «только каландр»! Это очень сложно (чтобы представить), почему я создам экземпляр класса транзакций, чтобы иметь функциональность, которую мне предоставил «каландр»!

  4. (In) согласованность API Когда я делаю book_a_ticket () - я бронирую билет! Это очень просто, независимо от того, сколько проверок и процессов происходит, чтобы это произошло. Теперь он становится сложным, когда поток времени начинает действовать. Обычно можно разрешить «поиск» и возможный доступный /недоступный статус, а затем, чтобы уменьшить назад, вы начинаете сохранять некоторые указатели контекста внутри билета, а затем отсылать , чтобы забронировать билет. Поиск не является единственной функциональностью - все становится хуже после многих таких «боковых функциональных возможностей». В этом процессе значение book_a_ticket () подразумевает book_that_ticket ()! и , что может быть невообразимо сложным.

Возможно, таких ситуаций вы бы видели в очень развитом коде, и я уверен, что многие люди могут добавлять сценарии, где «так много методов» просто не имеет смысла или не делает то, что вы, очевидно, думаете , Это анти-шаблон.

Мой личный опыт заключается в том, что когда проекты, которые начинают разумно снизу вверх, многие вещи, для которых должны были быть подлинные классы сами по себе- погребенные или худшие до сих пор остаются разделенными между разными классами и увеличением сцепления. Чаще всего то, что заслуживало бы 10 классов, но имеет только 4, вполне вероятно, что многие из них имеют многоцелевое запутывающее и большое количество методов. Назовите это БОГОМ и ДРАКОН, вот что ПЛОХО.

НО вы сталкиваетесь с классами ОЧЕНЬ БОЛЬШОГО, которые аккуратно согласованы, у них есть 30 методов - и все еще очень ЧИСТЫЕ. Они могут быть хорошими.

ответил Dipan Mehta 10 42011vEurope/Moscow11bEurope/MoscowThu, 10 Nov 2011 16:25:00 +0400 2011, 16:25:00
7

Классы должны иметь точное количество интерфейсов; не более, не менее.

Говорить «слишком много» было бы невозможно, не глядя на то, действительно ли все эти интерфейсы служат полезной цели в этом классе. Объявление того, что объект реализует интерфейс, означает, что вы должны реализовать его методы, если вы ожидаете, что класс будет компилироваться. (Я предполагаю, что класс, на который вы смотрите, делает это.) Если все в интерфейсе реализовано, и эти реализации делают что-то относительно интранов класса, было бы трудно сказать, что реализации не должно быть. Единственный случай, когда я могу думать о том, где интерфейс, отвечающий этим критериям, не будет принадлежать, является внешним: когда его никто не использует.

Некоторые языки позволяют «подклассифицировать» интерфейсы с помощью механизма, такого как ключевое слово Java extends, и тот, кто его написал, возможно, не знал, что , Также может быть, что все 23 достаточно обширны, что их объединение не имеет смысла.

ответил Blrfl 3 42011vEurope/Moscow11bEurope/MoscowThu, 03 Nov 2011 22:13:05 +0400 2011, 22:13:05
1

Звучит так, как будто у них есть пара «getter» /«setter» для каждого свойства, что является обычным для типичного «bean» и продвигает все эти методы в интерфейс. Итак, как насчет того, чтобы называть его « имеет bean-компонент ». Или более раблезианская «метеоризм» после хорошо известных аффектов слишком большого количества бобов.

ответил James Anderson 10 42011vEurope/Moscow11bEurope/MoscowThu, 10 Nov 2011 07:17:58 +0400 2011, 07:17:58
1

Количество интерфейсов часто растет, когда общий объект используется в разных средах. В C # варианты IComparable, IEqualityComparer и IComparer позволяют сортировать в разных настройках, поэтому вы можете завершить их реализацию, некоторые из них, возможно, более одного раза, поскольку вы можете реализовать типичные строго типизированные версии, а также не общие версии , кроме того, вы можете реализовать более одного из генериков.

Возьмем примерный сценарий, скажем, интернет-магазин, где вы можете купить кредиты, с помощью которых вы можете купить что-то еще (сайты с фотоснимками часто используют эту схему). У вас может быть класс «Valuta» и класс «Credits», которые наследуют одну и ту же базу. У Valuta есть некоторые изящные перегрузки операторов и процедуры сравнения, которые позволяют выполнять вычисления, не беспокоясь о свойстве «Валюта» (например, добавив килограммы к доллару). Кредиты распределяются проще, но имеют некоторые другие отличительные характеристики. Желая иметь возможность сравнивать их друг с другом, вы можете в конечном итоге реализовать IComparable, а также IComparable и другие варианты интерфейсов сравнения на обоих (хотя они используют общую реализацию, будь то в базовом классе или где-то еще).

При внедрении сериализации выполняется ISERializable, IDeserializationCallback. Затем реализуется стоп-кадр отмены: добавляется IClonable. IsDirty: IObservable, INotifyPropertyChanged. Позволяет пользователям редактировать значения с помощью строк: IConvertable ... Список можно продолжать и продолжать ...

В современных языках мы видим другую тенденцию, которая помогает разделить эти аспекты и разместить их в своих классах вне основного класса. Внешний класс или аспект затем ассоциируется с целевым классом с помощью аннотации (атрибутов). Часто можно сделать классы внешнего аспекта более или менее универсальными.

Использование атрибутов (аннотации) может быть отражено. Одним из недостатков является незначительная (начальная) потеря производительности. (Часто эмоциональный) недостаток заключается в том, что принципы, такие как инкапсуляция, должны быть расслаблены.

Есть всегда другие решения, но для каждого отличного решения есть компромисс или улов. Например, использование ORM-решения может потребовать объявления всех свойств виртуальными. Решения Serialization могут потребовать конструкторы по умолчанию для ваших классов. Если вы используете инъекцию зависимостей, вы можете реализовать 23 интерфейса в одном классе.

В моих глазах 23 интерфейса не должны быть плохими по определению. Там может быть хорошо продуманная схема, или какое-то принципиальное определение, например, избегать использования рефлексии или крайних инкапсулирующих убеждений.

Всякий раз, когда вы переключаете работу или работаете на существующей архитектуре. Мой совет - сначала познакомиться, не пытаться реорганизовать все слишком быстро. Послушайте оригинального разработчика (если он все еще там) и попытайтесь выяснить мысли и идеи, стоящие за тем, что вы видите. Когда вы задаете вопросы, сделайте это не ради разрушения, а для того, чтобы узнать ... Да, у каждого свои золотые молотки, но чем больше молотков вы можете собрать, тем легче вы будете ладить с коллегами.

ответил Louis Somers 15 22011vEurope/Moscow11bEurope/MoscowTue, 15 Nov 2011 23:32:27 +0400 2011, 23:32:27
0

«Слишком много» субъективно: стиль программирования? представление? соответствие стандартам? Прецеденты? просто ощущение комфорта /уверенности?

Пока ваш код ведет себя правильно и не представляет проблем с ремонтопригодностью, 23 может даже стать новой нормой. Когда-нибудь я смогу сказать: «Вы можете сделать отличную работу с 23 интерфейсами, см .: Jonas Elfström».

ответил Kris 15 22011vEurope/Moscow11bEurope/MoscowTue, 15 Nov 2011 14:24:50 +0400 2011, 14:24:50

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132