Как избежать общих имен для абстрактных классов?

10

В общем, хорошо избегать таких слов, как «handle» или «process», как части имен рутины и имен классов, если вы не имеете дело с (например) дескрипторами файлов или (например) процессами unix. Однако абстрактные классы часто не знают, что они собираются делать с чем-то, кроме, скажем, обработки. В моей текущей ситуации у меня есть «EmailProcessor», который входит в почтовый ящик пользователя и обрабатывает сообщения от него. Мне не совсем понятно, как дать этому более точное имя, хотя я заметил, что возникает следующий вопрос стиля:

  • лучше относиться к производным классам как к клиентам и называть базовый класс частью той функциональности, которую он реализует? Придает ему больше смысла, но нарушит его. Например, EmailAcquirer будет разумным именем, так как он получает для производного класса, но производный класс не будет получать для кого-либо.
  • Или просто смутное имя, так как кто знает, что будут делать производные классы. Однако «Процессор» все еще слишком общий, поскольку он выполняет много соответствующих операций, таких как вход в систему и использование IMAP.

Есть ли выход из этой дилеммы?

Проблема более очевидна для абстрактных методов, в которых вы не можете действительно ответить на вопрос "что это делает?" потому что ответ просто «все, что хочет клиент».

djechlin
источник
У вас есть источник (и некоторый контекст) для этого «общего» утверждения? Кроме того, дополнительное правило именования для списка - не тратьте время на поиск идеального имени, которое, вероятно, не существует. Если вы сомневаетесь, дайте ему лучшее имя, какое только можете, добавьте более подробное описание в качестве комментария, где оно будет определено, если это необходимо, но вы всегда можете рефакторинг позже, если кому-то не понравится ваш выбор, или вам идеально подойдет идеальное имя, когда вы ' делаю что-то еще.
Steve314
3
@ Steve314 - да, Стив Макконнелл, Code Complete, 1-е изд., Глава 4 или 5, о подпрограммах. Обширная дискуссия по именованию в этих главах, по существу, вывод, что если у вас нет хорошего имени, у вас, вероятно, нет хорошей функции.
Джечлин
Неспособность найти хорошее имя может показаться плохим признаком, но IMO вы должны знать, если функция плохая, основываясь на самой функции. Рефакторинг только потому, что английский язык не был специально разработан для вашего проекта, немного глуп. Нет, это не повседневная проблема, но вы уже решили, что у вас есть проблема.
Steve314
1
@ Steve314 Программирование полностью связано с управлением сложностью, и если ваш мозг не может придумать слово для чего-то, есть очень хороший шанс, что он не сможет справиться со сложностью этого, когда он должен делать такие вещи, как использовать его в большие предложения или как часть больших систем. На самом деле это не смелое заявление о том, что неспособность найти доброе имя - серьезная причина для беспокойства. Но это широко обсуждается в McConnell, я бы рекомендовал прочитать хотя бы эти две главы, хотя всю книгу стоит прочитать от корки до корки.
Джечлин
утверждениям в Code Complete не обязательно следует доверять. Я знаю о репутации книг, но я также знаю об этом . Кроме того, я прекрасно справлялся со сложностью целую вечность - ошибки случаются, конечно, но когда что-то идет не так, иногда проблема - это функция, которая настолько проста, что, очевидно, не может ошибаться, но в любом случае .
Steve314

Ответы:

10

Проблема не в названии, а в том, что вы вкладываете слишком много в один класс.

В вашем примере класса некоторые части очень конкретны (как будут получены письма). Другие части очень абстрактны (что вы будете делать с почтой).

Лучше делать это с отдельными классами, чем с наследованием.

Я предлагаю:

  • абстрактный MessageIterator, вложенный в класс POPMailBoxDownloader

  • другой класс, который СОБСТВЕННЫЙ POPMailBoxDownloader и делает что-то с сообщениями.

Крис Ван Баел
источник
Это звучит совершенно правильно. Похоже, если вы обнаружите, что называете что-то «processEvent» или класс «MessageProcessor», есть хороший шанс, что вы могли бы создать над композицией вместо деривации. В этом случае это компромисс, поскольку сопровождающим может быть полезна гибкость, но клиент будет раздражен, задаваясь вопросом, что конкретно делает каждая функция (более того, чем сопровождающий).
Джечлин
6

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

Если описание класса «Вход в почтовый ящик пользователя и обработка сообщений от него», я бы предложил «InboxProcessor» в качестве имени класса. Если производный класс имеет «Вход в почтовый ящик пользователя и перемещение спам-сообщения в папку спама» в качестве описания, я бы выбрал «InboxSpamMover» в качестве имени.

Я не вижу проблемы при использовании общих имен, таких как «процессор», если они отражают общее назначение абстрактного класса.

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

Тео Ленндорф
источник
2

Перефразируя Фрэнка Заппу, это то, что он есть и должен называться именно так. Ваш пример просто недостаточно глубоко вник в то, что происходит. Это EmailToTroubleTicketProcessor, EmailGrammarCorrectorили EmailSpamDetector?

Проблема более очевидна для абстрактных методов, в которых вы не можете действительно ответить на вопрос "что это делает?" потому что ответ просто «все, что хочет клиент».

Это не совсем верно; вопрос, на который вы не можете ответить за что-то абстрактное: « как он делает то, что делает?» потому что это зависит от реализации. Если у EmailSenderкласса есть DeliveryStatus deliver(Email e)метод, есть подразумеваемый контракт, что реализация получит электронное письмо, попытается доставить его и вернуть статус о том, как он прошел. Вам не важно, подключается ли он к SMTP-серверу или распечатывает его для привязки к почтовому голубю, если реализация выполняет то, что было обещано. Тезисы просто количественно определяют это обещание, чтобы реализация могла сказать: «Да, я делаю это».

Blrfl
источник
Как насчет того, когда конечная функция в некотором смысле является терминальной, так что абстрактный класс говорит: «И это здесь, делайте с ней что хотите»? например, метод не имеет доступа к состоянию, типу возврата void, без-броска.
Джечлин
Это все то же самое. Даже если ваш метод таков void doWhatYouDoWith(Email e), вы все равно можете вызывать класс an EmailDisposer, который достаточно конкретен, чтобы сказать, что он делает, но достаточно общий, как зависит от реализации. Хотя я думаю, что @KrisVanBael прибил это: если вы прибегли к чему-то неоднозначному, под одной крышей может быть слишком много.
Blrfl
0

Подумайте, почему плохо использовать такие слова. Они описательные? Какие слова есть, чтобы описать классы? EmailBaseClass? Может ли это быть более наглядным, чем, скажем, EmailManager или что-то подобное? Ключ должен иметь представление о рассматриваемом классе, так что найдите правильные глаголы или существительные. Относитесь к своему коду, как к поэзии.

zxcdw
источник
«EmailBaseClass» был бы похож на int age«ageInteger», только еще хуже, поскольку я ожидал, что из него будут извлекаться простые текстовые электронные письма, электронные письма MIME и т. Д. Нет необходимости описывать то, что предшествует слову abstractв первую очередь (это Java). У вас есть какое-то конкретное понимание базовой части этого класса? И более глубокое понимание по-прежнему не решает проблему именования чего-то, что будет пересекать отношения "я-это", у меня может быть что-то слишком расплывчатое или слишком общее, я не вижу выхода из этого, если, если бы у меня не было больше понимания, чтобы иметь больше понимания.
Джечлин
@djechlin - есть редкие случаи, когда ageIntegerили что-то подобное действительно уместно. Венгерская нотация - это сокращенная версия из контекста, где это часто случалось. Конечно, бывают случаи, когда вам может понадобиться что-то по аналогии ageNumericи ageStringв той же области, причем указание типа в имени является самым простым и понятным способом устранения неоднозначности.
Steve314
@djechlin Лично мне проще всего работать с кодом, на который я могу просто взглянуть, чтобы получить понимание. То есть имена говорят мне, с чем я работаю. Не нужно знать, systemControllerявляется ли это абстрактный базовый класс или лист в огромной иерархии. Конечно, это можно исправить с помощью IDE (как, я полагаю, имеет место в большинстве случаев разработки на Java?), Которая может немедленно информировать пользователя о содержимом и структуре класса, так что на самом деле проницательные имена не могут быть оправданы подобным образом.
zxcdw