Есть ли что-то не так с классом со всеми статическими методами?

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

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

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

ОБНОВЛЕНИЕ: конкретное состояние, которое раздается, является набором результатов от базы данных. Ответственность класса состоит в том, чтобы заполнить шаблон электронной таблицы Excel от набора результатов от DB. Я не знаю, имеет ли это какое-либо значение.

45
задан MatthewMartin 18 March 2010 в 14:44
поделиться

16 ответов

Что-то не так с этим шаблоном ? Является ли это вопросом личного выбора , если состояние класса хранится в полях и свойствах или передается среди статических методов с использованием аргументов?

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

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

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

Напротив, многие языки функционального программирования, даже объектно-ориентированные, такие как F # и OCaml (и C #!), Поощряют плоский и неглубокий иерархия. Библиотеки на этих языках, как правило, обладают следующими свойствами:

  • Большинство объектов являются объектами POCO или имеют не более одного или двух уровней наследования, где объекты не более чем контейнеры для логически связанных данных.
  • Вместо вызовов друг друга классов у вас есть модули (эквивалентные статическим классам), управляющие взаимодействием между объектами.
  • Модули, как правило, работают с очень ограниченным числом типов данных, и поэтому имеют узкую область применения.Например, модуль OCaml List представляет операции со списками, а модуль «Клиент» упрощает операции с клиентами. Хотя модули имеют более или менее ту же функциональность, что и методы экземпляра в классе, ключевое отличие от модульных библиотек состоит в том, что модули намного более автономны, гораздо менее детализированы и, как правило, имеют мало зависимостей от других модулей.
  • Обычно нет необходимости создавать подклассы объектов, замещающих методы, поскольку вы можете передавать функции как объекты первого класса для специализации.
  • Хотя C # не поддерживает эту функциональность, функторы предоставляют средства для создания подклассов специализированных модулей.

Большинство больших библиотек имеют тенденцию быть более широкими, чем глубокими, например Win32 API, библиотеки PHP, библиотеки Erlang BIF, библиотеки OCaml и Haskell, хранимые процедуры в базе данных и т. Д. Таким образом, этот стиль программирования является боевым тестированием и, похоже, хорошо работают в реальном мире.

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

20
ответ дан 26 November 2019 в 21:22
поделиться

Я не совсем понимаю, что вы имели в виду под методом входа, но если вы говорите о чем-то вроде этого:

 MyMethod myMethod = new MyMethod();
 myMethod.doSomething(1);

 public class MyMethod {
      public String doSomething(int a) {
          String p1 = MyMethod.functionA(a);
          String p2 = MyMethod.functionB(p1);
          return p1 + P2;
      }
      public static String functionA(...) {...}
      public static String functionB(...) {...}
 }

Это не рекомендуется.

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

 MyClass.myStaticMethod(....);

в отличие от:

 MyClass.getInstance().mySingletonMethod(...);

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

0
ответ дан 26 November 2019 в 21:22
поделиться

«Состояние класса ... передается среди статических методов с использованием аргументов?» Так работает процедурное программирование.

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

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

0
ответ дан 26 November 2019 в 21:22
поделиться

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

Однако есть несколько исключений:

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

Фактически, я считаю ключевое слово static тем, чем оно является: опцией, которую следует использовать с осторожностью, поскольку она нарушает некоторые принципы ООП.

1
ответ дан 26 November 2019 в 21:22
поделиться

An diesem Muster ist nichts auszusetzen. C # verfügt tatsächlich über ein Konstrukt namens statische Klassen, das verwendet wird, um diesen Begriff zu unterstützen, indem die Anforderung erzwungen wird, dass alle Methoden statisch sein müssen. Zusätzlich gibt es viele Klassen im Framework, die diese Funktion haben: Enumerable, Math, etc ...

2
ответ дан 26 November 2019 в 21:22
поделиться

Это зависит от того, действительно ли переданные аргументы могут быть классифицированы как state.

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

public static File loadConfiguration(String name, Enum type) {
    String fileName = (form file name based on name and type);
    return loadFile(fileName); // static method in the same class
}
1
ответ дан 26 November 2019 в 21:22
поделиться

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

Одна вещь, которую следует учитывать в C #, заключается в том, что многие классы, ранее написанные полностью статическими, теперь могут рассматриваться как классы расширения .net, которые также по своей сути остаются статическими классами. Многие расширения Linq основаны на этом.

Пример:

namespace Utils {
    public static class IntUtils        {
            public static bool IsLessThanZero(this int source)
            {
                return (source < 0);
            }
    }
}

Что затем позволяет вам просто делать следующее:

var intTest = 0;
var blNegative = intTest.IsLessThanZero();
2
ответ дан 26 November 2019 в 21:22
поделиться

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

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

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

3
ответ дан 26 November 2019 в 21:22
поделиться

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

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

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

4
ответ дан 26 November 2019 в 21:22
поделиться

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

Если мы говорим о классе с такими служебными методами, как Math.floor (), это не проблема. Но если класс является реальной зависимостью, например, объектом доступа к данным, то он привязывает всех своих клиентов к своей реализации.

РЕДАКТИРОВАТЬ: Я не согласен с людьми, которые говорят, что «нет ничего плохого» в этом типе «структурированного программирования». Я бы сказал, что такой класс - это, по крайней мере, запах кода, когда он встречается в обычном Java-проекте, и, вероятно, указывает на непонимание объектно-ориентированного дизайна со стороны создателя.

3
ответ дан 26 November 2019 в 21:22
поделиться

В этом нет ничего плохого. Это более «функциональный» способ программирования. Может быть проще протестировать (потому что нет внутреннего состояния) и повысить производительность во время выполнения (потому что нет накладных расходов на создание экземпляра в противном случае бесполезного объекта).

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

2
ответ дан 26 November 2019 в 21:22
поделиться

Поможет ли перефразировать вопрос:

Можете ли вы описать данные, над которыми работают статические методы, как сущность, имеющую:

  • четкое значение
  • ответственность за сохранение своего внутреннего состояния.

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

5
ответ дан 26 November 2019 в 21:22
поделиться

То, что вы описываете, является просто структурированным программированием, как это можно было бы сделать в C, Pascal или Algol. В этом нет ничего плохого. Есть ситуации, когда ООП более подходит, но ООП не является окончательным ответом, и если рассматриваемая проблема лучше всего обслуживается структурированным программированием, то класс, полный статических методов, - это путь.

21
ответ дан 26 November 2019 в 21:22
поделиться

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

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

2
ответ дан 26 November 2019 в 21:22
поделиться

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

0
ответ дан 26 November 2019 в 21:22
поделиться

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

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

1
ответ дан 26 November 2019 в 21:22
поделиться