2010-03-18 4 views
45

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

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

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

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

+1

http://www.stackoverflow.com/questions/790281/ –

+1

Также http://stackoverflow.com/questions/2410584/is-it-ok-to-wind-up-using-mostly-static-classes/ 2410849 # 2410849 – ewernli

+1

После вашего редактирования я бы сказал, что да, определенно должен быть экземплярным классом, потому что вы поддерживаете состояние (электронную таблицу Excel), поэтому у меня будет класс, который принимает ваш результат в конструкторе, а другой метод «Сохранить (имя файла строки)» или «Сохранить (Worksheet excel)», чтобы создать электронную таблицу Excel. Все другие методы, которые я предполагаю, являются вспомогательными методами и должны быть частными. –

ответ

20

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

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

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

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

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

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

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

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

+0

Ваш последний вопрос говорит со мной. Я полагаю, что ООП можно писать на процедурных языках и процедурно на языках ООП и, возможно, даже пытаться написать функциональный или динамический стиль в ООП или процедурный язык. Во всех случаях это будет писать код, который борется с каркасом, в котором он находится, и будет труднее читать для программиста, ожидающего ООП в программе Java или C#. – MatthewMartin

+9

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

+2

+1 «кирпичная стена, за которой следует гора» –

5

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

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

  • ясный смысл
  • ответственность за сохранение его внутреннего состояния последовательны.

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

3

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

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

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

+2

Не синглтон довольно устаревший шаблон с IoC? –

+0

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

1

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

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

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 
} 
2

В этом шаблоне нет ничего плохого. C# на самом деле имеет конструкцию, называемую статическими классами, которая используется для поддержки этого понятия, применяя требование о том, чтобы все методы были статическими. Кроме того, в структуре есть много классов, которые имеют эту функцию: Enumerable, Math и т. Д.

1

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

Там, однако, есть несколько исключений:

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

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

2

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

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

21

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

+0

Точно, нет ничего инстинктивно плохого при выполнении структурированного программирования на языке OO. Но один из них по существу тратит много сил, таких как использование класса и реализации в качестве базовых случаев для более специализированного поведения с использованием наследования и т. Д. –

+1

+1, только потому, что у вас есть бензопила, это не означает, что каждая проблема лучше всего решается с помощью бензопила. Иногда вам действительно нужен молот. Иногда проще просто сохранить это. – wasatz

+0

+1 за то, что вопрос состоит в просто структурированном программировании. Сантехника между Excel и a, позвольте мне догадаться, реляционная БД? Это не OO. Пока вам не нужно OO, и вы не называете это OO, нет проблемы. – SyntaxT3rr0r

0

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

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

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

2

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

Одна вещь, которую следует учитывать в 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(); 
+0

Pedantic note - должен ли он быть «источником возврата <0», поскольку intVal является типом? (И скобки не являются строго необходимыми, хотя и полезными для удобочитаемости.) –

+0

oops, я набрал слишком быстро :-), исправил соответственно. –

0

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

0

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

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(...); 

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

3

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

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

EDIT: Я не согласен с тем, что люди говорят «нет ничего плохого» в этом «структурированном программировании». Я бы сказал, что такой класс, по крайней мере, является запахом кода, когда встречается в рамках обычного Java-проекта, и, вероятно, указывает на непонимание объектно-ориентированного дизайна со стороны создателя.

+1

«вероятно, указывает на непонимание объектно-ориентированного дизайна» ... или, они просто не верят, что весь код должен быть OO. –

+2

Традиционно вы должны передавать все зависимости, которые вам нужны, в статический класс, поэтому методы могут иметь больше параметров, но вы можете легко тестировать любые зависимости. Хорошее программирование на основе модулей обескураживает жесткую модульную связь, поэтому у вас обычно нет модулей, вызывающих другие модули, но в случае, если вы это сделаете, вы должны переписать 'static void A (someState) {B.HandleState (someState)}' как ' static void A (somestate, handleState) {handleState (someState)} ', поэтому может заменить вашу функцию обработчика любой желаемой реализацией, включая вызов исходного модуля обработчика или макет. – Juliet

+0

@Adriaan Koster: +1 ... Единичное тестирование этого класса или притворство этой «абстракции» оказалось бы очень трудным. – SyntaxT3rr0r

4

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

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

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

2

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

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

1

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

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

Смежные вопросы