Объект бога - уменьшение, связывающееся с 'основным' объектом

C ++ - это язык более низкого уровня, который выполняется без контекста интерпретатора. Таким образом, он имеет много других вариантов дизайна, чем Python, потому что в C ++ нет среды, на которую он может полагаться при управлении информацией, такой как типы и память. C ++ может использоваться для написания ядра операционной системы, где на машине не выполняется код, за исключением самой программы, что означает, что язык (некоторые библиотечные средства недоступны для так называемых автономных реализаций) должен быть автономным. Вот почему C ++ не имеет эквивалента Python eval, ни средств определения членов и т. Д. Класса, ни других функций, которые требуют среды выполнения (или огромных накладных расходов в самой программе вместо такой среды)

Для ваших индивидуальных вопросов:

  • вы должны включать <iostream> каждый раз? Вам это никогда не нужно?

#include <iostream> - это директива, которая импортирует заголовок <iostream> в вашу программу. <iostream> содержит стандартные объекты ввода / вывода - в частности, cout. Если вы не используете стандартные объекты ввода / вывода (например, вы используете только файловый ввод / вывод, или ваша программа использует библиотеку графического интерфейса пользователя или пишет ядро ​​операционной системы), вам не нужно <iostream>

  • тот же вопрос для стандартной библиотеки, когда вам не нужен std :: *?

std пространство имен, содержащее всю стандартную библиотеку. using namespace std; похоже на from std import *, тогда как директива #include (в этом отношении) больше похожа на утверждение barebones import std. (На самом деле механизм несколько иной, потому что C ++ не использует using namespace std; для автоматического поиска объектов в std; директива using только импортирует имена в глобальное пространство имен.)

I ' Отметим здесь, что директивы using (using namespace) часто не одобряются в коде C ++, поскольку они импортируют много имен и могут вызывать конфликты имен. Правила использования (using std::cout;) предпочтительны, когда это возможно, так как ограничивают область действия директивы использования (например, одной функцией или одним исходным файлом). Никогда не помещайте using namespace в заголовок без уважительной причины.

  • Является ли «основная» часть функцией? Вы когда-нибудь вызывали основную функцию? Почему это целое число? Почему в C ++ должна быть основная функция, а в Python нет?

main - это точка входа в программу, с которой начинается выполнение. В Python модуль __main__ служит той же цели. C ++ не выполняет код вне определенной функции, как это делает Python, поэтому его точкой входа является функция, а не модуль.

  • Вам нужен "std :: cout < <"? Разве это не слишком долго и сложно по сравнению с Python?

std::cout необходимо только в том случае, если вы не импортируете имя cout в глобальное пространство имен, либо с помощью директивы using ( using namespace std;) или с помощью декларации об использовании (using std::cout). В этом отношении это снова очень похоже на различие между import std и from std import * или from std import cout Python

.

<< является перегруженным оператором для стандартных потоковых объектов. cout << value вызывает функцию cout для вывода value. Python не нуждается в таком дополнительном коде, потому что print встроен в язык; это не имеет смысла для C ++, где может даже не быть операционной системы, тем более библиотеки ввода-вывода.

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

Нет. main (и никакой другой функции) в конце имеет неявное значение return 0;. Возвращаемое значение main (или, если вызывается функция exit, передаваемое ему значение) передается обратно в операционную систему в качестве кода выхода. 0 указывает на то, что программа успешно выполнена - что она не обнаружила ошибок и т. Д. Если обнаружена ошибка, должно быть возвращено ненулевое значение (или передано в exit).

8
задан James A Mohler 20 March 2013 в 18:25
поделиться

6 ответов

Во-первых, рискуя заявить очевидное: передавайте параметры, которые используются методами, а не объект god.

Это, однако, может привести к тому, что некоторые методы потребуют огромных количество параметров, потому что они вызывают другие методы, которые, в свою очередь, вызывают другие методы и т. д. Вероятно, это было вдохновением для того, чтобы поместить все в божественный объект. Я приведу упрощенный пример такого метода со слишком большим количеством параметров; вы должны представить, что здесь "too many" == 3 :-)

public void PrintFilteredReport(
   Data data, FilterCriteria criteria, ReportFormat format)
{
   var filteredData = Filter(data, criteria);
   PrintReport(filteredData, format);
}

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

// dataFilter service object only needs to know the criteria
var dataFilter = new DataFilter(criteria);

// report printer service object only needs to know the format
var reportPrinter = new ReportPrinter(format);

// filteredReportPrinter service object is initialized with a
// dataFilter and a reportPrinter service, but it doesn't need
// to know which parameters those are using to do their job
var filteredReportPrinter = new FilteredReportPrinter(dataFilter, reportPrinter);

Теперь метод FilteredReportPrinter.Print может быть реализован только с одним параметром:

public void Print(data)
{
   var filteredData = this.dataFilter.Filter(data);
   this.reportPrinter.Print(filteredData);
}

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

  • очень гибким: вы можете настроить FilteredReportPrinter с любой реализацией фильтра / принтера, которую вы можете себе представить
  • , очень тестируемой: вы можете передать имитацию соавторов с шаблонными ответами и проверить что они использовались правильно в модульном тесте
9
ответ дан 5 December 2019 в 20:17
поделиться

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

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

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

Трудно дать хорошее решение без некоторых примеров кода и реальных ситуаций.

1
ответ дан 5 December 2019 в 20:17
поделиться

It sounds like you are not applying object-oriented (OO) principles in your design. Since you mention the word "object" I presume you are working within some sort of OO paradigm. I recommend you convert your "call tree" into objects that model the problem you are solving. A "god object" is definitely something to avoid. I think you may be missing something fundamental... If you post some code examples I may be able to answer in more detail.

0
ответ дан 5 December 2019 в 20:17
поделиться

Запрашивать у каждого клиента необходимые параметры и вводить их?

Пример: каждый «объект», требующий «параметров», является «Клиентом». Каждый «Клиент» предоставляет интерфейс, через который «Агент конфигурации» запрашивает у Клиента необходимые параметры. Затем агент конфигурации "вводит" параметры (и только те, которые требуются клиенту).

0
ответ дан 5 December 2019 в 20:17
поделиться

Для параметров, определяющих поведение, можно создать экземпляр объекта, который демонстрирует настроенное поведение. Затем клиентские классы просто используют созданный объект - ни клиент, ни служба не должны знать, каково значение параметра. Например, для параметра, который сообщает, откуда читать данные, все FlatFileReader, XMLFileReader и DatabaseReader наследуют один и тот же базовый класс (или реализуют один и тот же интерфейс). Создайте один из них на основе значения параметра, тогда клиенты класса считывателя просто запрашивают данные у созданного экземпляра объекта считывателя, не зная, поступают ли данные из файла или из БД.

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

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

0
ответ дан 5 December 2019 в 20:17
поделиться

(I am assuming this is within a Java or .NET environment) Convert the class into a singleton. Add a static method called "getInstance()" or something similar to call to get the name-value bundle (and stop "tramping" it around -- see Ch. 10 of "Code Complete" book).

Now the hard part. Presumably, this is within a web app or some other non batch/single-thread environment. So, to get access to the right instance when the object is not really a true singleton, you have to hide selection logic inside of the static accessor.

In java, you can set up a "thread local" reference, and initialize it when each request or sub-task starts. Then, code the accessor in terms of that thread-local. I don't know if something analogous exists in .NET, but you can always fake it with a Dictionary (Hash, Map) which uses the current thread instance as the key.

It's a start... (there's always decomposition of the blob itself, but I built a framework that has a very similar semi-global value-store within it)

-2
ответ дан 5 December 2019 в 20:17
поделиться