Является ли хорошей практикой писать классы, в которых обычно используется только один открытый метод? - PullRequest
4 голосов
/ 16 июля 2010

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

Это типично для попыток сделать что-то в стиле TDD?Я боюсь, что теперь я реорганизовал унаследованный класс из 3000 строк, в котором был один метод, во что-то, что также трудно поддерживать на другой стороне спектра, потому что теперь существует буквально около 100 различных файлов классов.

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

Ответы [ 4 ]

2 голосов
/ 16 июля 2010

Это множество маленьких классов сведет меня с ума. С этим стилем дизайна становится действительно трудно понять, где настоящая работа сделана. Я не фанат наличия тонны интерфейсов с соответствующим классом реализации. Наличие большого количества пар «IWidget» и «WidgetImpl» - это запах кода в моей книге.

Разделение 3000-строчного класса на более мелкие части - это замечательно и похвально. Помните о цели: сделать код проще для чтения и с ним легче работать. Если у вас 30 классов и интерфейсов, вы, вероятно, просто создали монстров другого типа. Теперь у вас действительно сложный дизайн класса. Требуется много умственных усилий, чтобы держать столько уроков прямо в голове. А с множеством небольших классов вы теряете очень полезную возможность открыть пару ключевых файлов, выбрать наиболее важные методы и понять, что происходит, черт возьми.

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

1 голос
/ 16 июля 2010

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

0 голосов
/ 16 июля 2010

Я бы размышлял, если бы дал определенный ответ, не глядя на код.

Однако, похоже, что вы обеспокоены, и это определенный флаг для проверки кода. Краткий ответ на ваш вопрос возвращается к определению Simple Design . Минимальное количество классов и методов является одним из них. Если вы чувствуете, что можете убрать некоторые элементы, не теряя других желательных атрибутов, продолжайте свернуть / вставить их.

Некоторые указатели, которые помогут вам решить:

  • У вас есть хороший чек на "Одиночная ответственность"? Это обманчиво сложно понять правильно, но это ключевой навык (я до сих пор не вижу его как мастера). Это не обязательно переводить в один метод-классы. Хороший критерий - 5-7 открытых методов на класс. Каждый класс может иметь 0-5 сотрудников. Также для проверки по SRP задайте вопрос, что может привести к изменениям в этом классе? Если существует несколько несвязанных ответов (например, изменение в структуре пакета (разбор) + изменение содержимого пакета на карту действий (диспетчер команд)), возможно, класс необходимо разделить. С другой стороны, если вы чувствуете, что изменение в структуре пакета может повлиять на 4 разных класса - вы сбежали с другого утеса; может быть, вам нужно объединить их в единый класс.
  • Если вам сложно назвать конкретные реализации, возможно, вам не нужен интерфейс. например XXXImpl классы, реализующие XXX необходимо посмотреть. Недавно я узнал о соглашении об именах, в котором интерфейс описывает роль, а реализация названа технологией, используемой для реализации роли (или отступает к тому, что она делает). например XmppAuction реализует Аукцион (или SniperNotifier реализует AuctionEventListener)
  • Наконец, вам трудно добавить / изменить / протестировать существующий код (например, установка теста длинна или болезненна)? Это могут быть признаки того, что вам нужно провести рефакторинг.
0 голосов
/ 16 июля 2010

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

Если у вас нет состояния, вам не нужен класс, вы можете просто использовать свободные функции (или в Java - статические функции).

Итак, вопрос не в том, должна ли я иметь одну функцию? а точнее "какая сущность с полным состоянием инкапсулирует мой класс?"

Может быть, у вас есть одна функция, которая устанавливает все состояния - и вы должны сделать ее более детальной, чтобы, например, вместо void Rectangle::setWidthAndHeight( int x, int y) у вас был setWidth и отдельный setHeight.

Возможно, у вас есть ctor, который настраивает вещи, и одна функция, которая doesIt, что бы это ни было. Тогда у вас есть функтор , и один doIt может иметь смысл. Например, class Add implements Operation { Add( int howmuch); Operand doIt(Operand rhs);}

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

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

Там нет одного ответа. Если у вас действительно есть куча функторов, это круто. Если вы действительно просто делаете каждую свободную функцию классом, это глупо.

Реальный ответ заключается в ответе на вопрос: «В каком состоянии я управляю, и насколько хорошо мои классы моделируют мою проблемную область?»

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...