Классы для предотвращения (кодируют завершенный),

Я несколько смущен абзацем в коде полная книга.

В разделе "Classes to avoid" это читает:

"Избегайте классов, названных в честь глаголов класс, который имеет только поведение, но никакие данные обычно не являются не действительно классом. Рассмотрите превращение класса как DatabaseInitialization () или StringBuilder () в стандартную программу на некотором другом классе"

Мой код главным образом состоит из классов глагола без данных. Существуют invoicereaders, pricecalculators, messagebuilders и т.д. Я делаю это для концентрации классов к одной задаче каждый. Затем я добавляю зависимости к другим классам для другой функциональности.

Если я понимаю абзац правильно, я должен использовать код как

class Webservice : IInvoiceReader, IArticleReader {
    public IList<Invoice> GetInvoices();
    public IList<Article> GetArticles();
}

вместо

class InvoiceReader : IInvoiceReader {
    public InvoiceReader(IDataProvider dataProvider);
    public IList<Invoice> GetInvoices();
}

class ArticleReader : IArticleReader {
    public ArticleReader(IDataProvider dataProvider);
    public IList<Article> GetArticles();
}

Редактирование спасибо за все ответы.

Мое заключение состоит в том, что моим текущим кодом является больше SRP, чем OO, но что это также страдает от "анемичной модели предметной области".

Я уверен, что понимание тезисов поможет мне в будущем.

38
задан adrianm 23 January 2010 в 11:06
поделиться

10 ответов

Названия классов, такие как InvoiceReader, PriceCulculator, MessageBuilder, Articlereader, InvoiceReader - это не имена глаголов. Они действительно «имена имена класса Agent-Noun». Смотреть существительные агента .

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

Самая большая проблема с именами классов «Существительное агента - существительное» заключается в том, что они могут дать очень мало смысла относительно того, что делает класс на самом деле (например, Usermanager, DataProcessor etc). В результате они чаще будут раздутыми и потерять внутреннюю сплоченность. (См. Принцип одной ответственности ).

Поэтому класс WebService с интерфейсами IinVoiceReader и IInticlereader, вероятно, является более четким и более значимым дизайном OO.

Это дает вам простое, очевидное имя существительного класса «Webservice», а также имена интерфейсных интерфейсов «Noun agent-noun», которые четко рекламируют, что класс WebService может сделать для абонентов.

Вы также можете также дать больше смысла к фактическому классу, префиксировав другое существительное, например ProjectWebservice.

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

20
ответ дан 27 November 2019 в 03:52
поделиться

Не следуйте никаким советам вслепую. Это только рекомендации.

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

5
ответ дан 27 November 2019 в 03:52
поделиться

Обратите внимание на использование слова «Избегайте». Он не устраняет, или искореняет, или горит в аду, если вы когда-нибудь используете их.

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

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

Как предложил автор, в тех случаях, в этих случаях хороший способ сделать это, создавая интерфейс и реализовать его. Imparer <> снова приходит в голову.

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

3
ответ дан 27 November 2019 в 03:52
поделиться

, В первую очередь, вы должны переписать как это:

class User(object):
  def __init__(self, username, password):
    self.username = username
    self.password = password

Таким образом, имя пользователя и пароль - переменные случая вместо переменных класса (в вашем примере, они - переменные класса - все переменные случая должны быть определены в __ init __ как свойства сам ). Затем можно инициализировать пользователя с любым требуемым именем пользователя и паролем, включая Нет , если вы действительно хотите, чтобы они не имели значения.

-121--1313159-

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

Существительные становятся объектами, глаголы - методами, которые оперируют этими объектами.

Идея в том, что

ближе программа моделирует реальное мировая проблема, чем лучше программа будет.

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

В случае класса InvoiveReader

  • создается только один экземпляр
  • , единственное состояние, которое он представляет, - это состояние, содержащее dataProvider
  • , он содержит только один метод

, нет преимущества поместить его в объект.

2
ответ дан 27 November 2019 в 03:52
поделиться

Я думаю, что книга предлагает дизайн, как следующее:

class Article : IIArticleReader
{
    // Article data...

    public IList<Article> GetArticles(); 
}
0
ответ дан 27 November 2019 в 03:52
поделиться

Ноябрьская версия Silverlight Toolkit содержит не только Silverlight Unit Testing Framework, но и задачу MSBuild, позволяющую запускать рамку из командной строки. Для получения подробной информации см. Сообщение Джеффа Уилкокса , но вы, по сути, делаете это:

msbuild /t:test /p:browser=firefox

Поскольку CC.Net может запустить MSBuild, вы должны иметь возможность хотя бы вызвать тесты. Выходные данные представлены в формате TRX.

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

-121--2856336-

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

Класс, который имеет только поведение, но нет данных, как правило, на самом деле не является классом

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

-121--1230855-

Это зависит. Существует много классов, названных в честь глаголов Read and Write, поскольку классы также создают, поддерживают и представляют соединение с источником данных, из которого они читают или записывают. Если ваши классы делают это, наверное, лучше держать их отдельно.

Если объекты Reader содержат только логику синтаксического анализа, то преобразование классов в служебные методы - это путь. Я бы пошел с более описательным именем, чем Webservice.

0
ответ дан 27 November 2019 в 03:52
поделиться

Сосредоточьтесь меньше на имени. Правило о названии - это всего лишь "эмпирическое" правило индикатора для плохой практики. Важный момент заключается в следующем:

Класс, который имеет только поведение, но не имеет данных, обычно не является классом

В вашем случае, это выглядит так, как будто ваши классы имеют и данные, и поведение, и что они также могут быть названы "Invoice" и "Article".

0
ответ дан 27 November 2019 в 03:52
поделиться

Вот классический взнос «глагол против существительного» в OO:

http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of- nouns.html

0
ответ дан 27 November 2019 в 03:52
поделиться

Заявление класс, который имеет только поведение, но никаких данных, как правило, не совсем класс. просто не так.

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

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

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

Например:

public interface IExporter
{
    /// <summary>
    /// Transforms the specified export data into a text stream.
    /// </summary>
    /// <param name="exportData">The export data.</param>
    /// <param name="outputFile">The output file.</param>
    void Transform(IExportData exportData, string outputFile);
}

может быть реализован как

class TabDelimitedExporter : IExporter { ... }
class CsvExporter : IExporter { ... }
class ExcelExporter : IExporter { ... }

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

[РЕДАКТИРОВАНИЕ]

Перемещение GetInvoices и GetArticles В класс WebService означает, что вы привязываете их реализацию в типе WebService. Наличие их в отдельных классах позволит вам иметь разные реализации как для счетов, так и для статей. В целом, кажется, что они отделились.

1
ответ дан 27 November 2019 в 03:52
поделиться

Я игнорирую это «правило», лично. Сама .NET Framework полна классов «глагола»: Textreader , , , , XMLSerializer , CodegEnator , StringEnumerator , HTTPLISTENER , TRACELISTENER , ConfigurationManager , TypeConverter , РольПровидер ... Если вы думаете, что Рамки плохо спроектированы, а затем все средства, не используйте такие имена.

Намерение Стива понятно. Если вы оказываете создание десятков на десятки классов, просто для выполнения определенной задачи, вероятно, является признаком модели модели анемии , где объекты, которые должны иметь возможность делать эти вещи сами по себе нет. Но в какой-то момент вы должны сделать выбор между «чистым» OOP и SRP .

Мое предложение было бы этим: если вы окажетесь создать класс «глагола», который действует на одном «существительном классе», честно думать о том, может ли класс «существительного» может выполнять действие самостоятельно. Но не начинайте создавать объекты Бога или придумывать бессмысленные / вводящие в заблуждение имена для единственной цели, чтобы избежать класса глагола.

11
ответ дан 27 November 2019 в 03:52
поделиться
Другие вопросы по тегам:

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