Я делаю обзор кода и столкнулся с классом, который использует все статические методы. Метод входа берет несколько аргументов и затем начинает называть другие статические методы, проводящие все или некоторые аргументы метод входа полученный.
Это не похоже на Математический класс с в основном несвязанными служебными функциями. В моем собственном нормальном программировании я редко пишу методы, где Resharper выталкивает и заявляет, что "это могло быть статическим методом", когда я делаю, они имеют тенденцию быть бессмысленными служебными методами.
Есть ли что-то не так с этим шаблоном? Это - просто вопрос личного выбора, если состояние класса сохранено в полях и свойствах или роздано среди статических методов с помощью аргументов?
ОБНОВЛЕНИЕ: конкретное состояние, которое раздается, является набором результатов от базы данных. Ответственность класса состоит в том, чтобы заполнить шаблон электронной таблицы Excel от набора результатов от DB. Я не знаю, имеет ли это какое-либо значение.
Что-то не так с этим шаблоном ? Является ли это вопросом личного выбора , если состояние класса хранится в полях и свойствах или передается среди статических методов с использованием аргументов?
Исходя из моего личного опыта, я работал над 100 приложениями KLOC, которые имеют очень глубокие иерархии объектов, все наследует и отменяет все остальное, все реализует полдюжины интерфейсов, даже интерфейсы наследуют полдюжины интерфейсов, система реализует все шаблоны проектирования, описанные в книге, и т. д.
Конечный результат: действительно ООП-архитектура с таким количеством уровней косвенности, что на отладку чего-либо уходит часы. Недавно я начал работать с такой системой, в которой кривая обучения описывалась мне как «кирпичная стена, за которой следует гора».
Иногда чрезмерное рвение ООП приводит к тому, что классы настолько детализированы, что фактически наносят чистый вред.
Напротив, многие языки функционального программирования, даже объектно-ориентированные, такие как F # и OCaml (и C #!), Поощряют плоский и неглубокий иерархия. Библиотеки на этих языках, как правило, обладают следующими свойствами:
Большинство больших библиотек имеют тенденцию быть более широкими, чем глубокими, например Win32 API, библиотеки PHP, библиотеки Erlang BIF, библиотеки OCaml и Haskell, хранимые процедуры в базе данных и т. Д. Таким образом, этот стиль программирования является боевым тестированием и, похоже, хорошо работают в реальном мире.
На мой взгляд, лучше всего разработанные API-интерфейсы на основе модулей, как правило, легче работать, чем лучше всего разработанные API-интерфейсы ООП. Однако стиль кодирования так же важен в разработке API, поэтому, если все остальные в вашей команде используют ООП, а кто-то уходит и реализует что-то в совершенно другом стиле, вам, вероятно, следует попросить переписать, чтобы более точно соответствовать кодированию вашей команды. стандарты.
Я не совсем понимаю, что вы имели в виду под методом входа, но если вы говорите о чем-то вроде этого:
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(...);
Все статические методы / синглтоны также обычно используют меньше памяти, но в зависимости от того, сколько у вас пользователей, вы можете даже не заметить этого.
«Состояние класса ... передается среди статических методов с использованием аргументов?» Так работает процедурное программирование.
Класс со всеми статическими методами и без переменных экземпляра (кроме статических конечных констант) обычно является служебным классом, например Math. Нет ничего плохого в создании класса unility (не в самом себе ) Кстати: если вы создаете служебный класс, вы можете предотвратить использование этого класса для создания объекта. в java это можно сделать, явно определив конструктор, но сделав конструктор закрытым. Хотя, как я уже сказал, нет ничего плохого в создании служебного класса, если основная часть работы выполняется выполняется с помощью служебного класса (который не является классом в обычном смысле - это скорее набор функций) , то это вероятно, как признак того, что проблема не была решена с использованием объектно-ориентированного парадима . это может быть хорошо, а может и нет
Метод входа принимает несколько аргументов, а затем начинает вызывать другие статические методы, передавая все или некоторые из аргументов, полученных методом входа. судя по звуку, весь класс фактически представляет собой один метод (это определенно будет иметь место, если все другие статические методы являются частными (и являются просто вспомогательными функциями), и здесь нет переменных экземпляра (исключение константы)) Это может быть и хорошо, Это esc. структурированное / процедурное программирование, довольно изящное, когда они (функция и ее помощник) объединены в один класс. (в C вы просто поместите их все в один файл и объявите статический помощник (это означает, что к нему нельзя получить доступ извне))
Лично я склонен думать, что метод, изменяющий состояние объекта, должен быть методом экземпляра этого класса объекта. Фактически, я считаю это практическим правилом: метод, изменяющий объект, является методом экземпляра этого класса объекта.
Однако есть несколько исключений:
Фактически, я считаю ключевое слово static тем, чем оно является: опцией, которую следует использовать с осторожностью, поскольку она нарушает некоторые принципы ООП.
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 ...
Это зависит от того, действительно ли переданные аргументы могут быть классифицированы как 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
}
Нет, многие люди склонны для создания полностью статических классов для служебных функций, которые они хотят сгруппировать в связанном пространстве имен. Есть много веских причин для использования полностью статических классов.
Одна вещь, которую следует учитывать в 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();
Я считаю, что если класс должен поддерживать некоторую форму состояния (например, свойства), то он должен быть создан (т.е. «нормальный» класс).
Если должен быть только один экземпляр этого класса (следовательно, все статические методы), то должно быть свойство/метод синглетона или фабричный метод, который создает экземпляр класса при первом его вызове, а затем просто предоставляет этот экземпляр, когда кто-либо другой запрашивает его.
Сказав это, это просто мое личное мнение и то, как я бы его реализовал. Я уверен, что другие не согласятся со мной. Не зная ничего больше, трудно привести причины за/против каждого метода, если честно.
Вот рабочий процесс рефакторинга, с которым я часто сталкиваюсь, и использующий статические методы. Это может дать некоторое представление о вашей проблеме.
Я начну с класса с достаточно хорошей инкапсуляцией. Когда я начинаю добавлять функции, я сталкиваюсь с частью функциональности, которая на самом деле не требует доступа к закрытым полям в моем классе, но, похоже, содержит связанные функции. После того, как это произойдет несколько раз (иногда только один раз), я начинаю видеть контуры нового класса в реализованных мной статических методах и то, как этот новый класс соотносится со старым классом, в котором я впервые реализовал статические методы.
Я вижу преимущество превращения этих статических методов в один или несколько классов в том, что когда вы это делаете, часто становится легче понимать и поддерживать ваше программное обеспечение.
Самая большая проблема, IMO, заключается в том, что если вы хотите, чтобы классы модульного тестирования, вызывающие упомянутый вами класс, невозможно было заменить эту зависимость. Таким образом, вы вынуждены одновременно тестировать и клиентский класс, и статически вызываемый класс.
Если мы говорим о классе с такими служебными методами, как Math.floor (), это не проблема. Но если класс является реальной зависимостью, например, объектом доступа к данным, то он привязывает всех своих клиентов к своей реализации.
РЕДАКТИРОВАТЬ: Я не согласен с людьми, которые говорят, что «нет ничего плохого» в этом типе «структурированного программирования». Я бы сказал, что такой класс - это, по крайней мере, запах кода, когда он встречается в обычном Java-проекте, и, вероятно, указывает на непонимание объектно-ориентированного дизайна со стороны создателя.
В этом нет ничего плохого. Это более «функциональный» способ программирования. Может быть проще протестировать (потому что нет внутреннего состояния) и повысить производительность во время выполнения (потому что нет накладных расходов на создание экземпляра в противном случае бесполезного объекта).
Но вы сразу теряете некоторые возможности объектно-ориентированного программирования Статические методы плохо реагируют (вообще) на наследование. Статический класс не может участвовать во многих шаблонах проектирования, таких как локатор фабрики / службы.
Поможет ли перефразировать вопрос:
Можете ли вы описать данные, над которыми работают статические методы, как сущность, имеющую:
В таком случае это должен быть инстанцированный объект, иначе это может быть просто набор связанных функций, как в математической библиотеке.
То, что вы описываете, является просто структурированным программированием, как это можно было бы сделать в C, Pascal или Algol. В этом нет ничего плохого. Есть ситуации, когда ООП более подходит, но ООП не является окончательным ответом, и если рассматриваемая проблема лучше всего обслуживается структурированным программированием, то класс, полный статических методов, - это путь.
Одним из недостатков использования статического класса является то, что его клиенты не могут заменить его тестовым двойником, чтобы пройти модульное тестирование.
Точно так же сложнее провести модульное тестирование статического класса, потому что его участники не могут быть заменены тестовыми двойниками (на самом деле это происходит со всеми классами, которые не внедряются зависимостями).
если нет необходимости создавать объект класса, тогда нет проблем с созданием всего метода как статического для этого класса, но я хочу знать, что вы делают с классом полно статических методов.
Передача всего состояния в качестве параметров метода может быть полезным шаблоном проектирования. Это гарантирует, что общее изменяемое состояние отсутствует, и поэтому класс по сути является потокобезопасным. Сервисы обычно реализуются с использованием этого шаблона.
Однако передача всего состояния через параметры метода не означает, что методы должны быть статическими - вы все равно можете использовать тот же шаблон с нестатическими методами. Преимущества создания статических методов заключаются в том, что вызывающий код может просто использовать класс, ссылаясь на него по имени. Нет необходимости в инъекции, поиске или другом посреднике. Недостатком является возможность обслуживания - статические методы не являются динамической диспетчеризацией, их нельзя легко разделить на подклассы или преобразовать в интерфейс. Я рекомендую использовать статические методы, когда существует только одна возможная реализация класса, и когда есть веская причина не использовать нестатические методы.