God object - уменьшение связи с "главным" объектом

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

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

Каковы некоторые хорошие методы для уменьшения связи с этим объектом Бога или в идеале его устранения ?

        public void ExporterExcelParFonds(ParametresExecution parametres)
    {
        ApplicationExcel appExcel = null;
        LogTool.Instance.ExceptionSoulevee = false;


        bool inclureReferences = parametres.inclureReferences;
        bool inclureBornes = parametres.inclureBornes;
        DateTime dateDebut = parametres.date;
        DateTime dateFin = parametres.dateFin;

        try
        {
            LogTool.Instance.AfficherMessage(Variables.msg_GenerationRapportPortefeuilleReference);

            bool fichiersPreparesAvecSucces = PreparerFichiers(parametres, Sections.exportExcelParFonds);
            if (!fichiersPreparesAvecSucces)
            {
                parametres.afficherRapportApresGeneration = false;
                LogTool.Instance.ExceptionSoulevee = true;
            }
            else
            {

абонент будет делать :

                PortefeuillesReference pr = new PortefeuillesReference();
            pr.ExporterExcelParFonds(parametres);

6 ответов


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

это, однако, может привести к тому, что некоторым методам потребуется огромное количество параметров, потому что они вызывают другие методы, которые, в свою очередь, вызывают другие методы и т. д. Это, вероятно, было вдохновением для того, чтобы поместить все в объект Бога. Я приведу упрощенный пример такого метода со слишком большим количеством параметров; вы должны представить, что "слишком много" = = 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.Способ печати может быть реализован только с одним параметр:

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

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

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

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

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

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

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


похоже, что вы не применяете объектно-ориентированные (ОО) принципы в своем дизайне. Поскольку вы упомянули слово "объект", я предполагаю, что вы работаете в какой-то парадигме ОО. Я рекомендую вам преобразовать ваше "дерево вызовов" в объекты, которые моделируют проблему, которую вы решаете. "Объект Бога" - это определенно то, чего следует избегать. Я думаю, вы упускаете что-то важное... Если вы опубликуете несколько примеров кода, я смогу ответить более подробно.


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

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


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

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

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


(Я предполагаю, что это находится в среде Java или .NET) преобразует класс в синглтон. Добавьте статический метод под названием "getInstance () "или что-то похожее на вызов, чтобы получить пакет name-value (и прекратите" топтать " его вокруг-см. Ch. 10 книги "Код завершен").

теперь трудная часть. Предположительно, это находится в веб-приложении или в какой-либо другой среде без пакета/одного потока. Итак, чтобы получить доступ к правильному экземпляру, когда объект на самом деле не является истинным синглтоном, вы нужно скрыть логику выбора внутри статического метода доступа.

в java вы можете настроить ссылку "локальный поток" и инициализировать ее при запуске каждого запроса или подзадачи. Затем кодируйте метод доступа в терминах этого потока-local. Я не знаю, существует ли что-то аналогичное в .NET, но вы всегда можете подделать его со словарем (хэш, карта), который использует текущий экземпляр потока в качестве ключа.

Это начало... (всегда есть разложение самого blob, но я построил каркас, который имеет очень похожие полу-глобального значения-магазине в нем)