2008-10-15 12 views
141

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

// Initialize arguments in constructor 
MyClass myObject = new MyClass(arg1, arg2, arg3); 
myObject.myMethod(); 

// Pass arguments to method 
MyClass myObject = new MyClass(); 
myObject.myMethod(arg1, arg2, arg3); 

// Pass arguments to static method 
MyClass.myMethod(arg1, arg2, arg3); 

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

ответ

224

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

полиморфизм
Скажем, у нас есть метод UtilityClass.SomeMethod, который счастливо гудит вместе. Внезапно нам нужно немного изменить функциональность. Большая часть функциональности одна и та же, но мы должны изменить пару частей, тем не менее. Если бы это не был статический метод, мы могли бы сделать класс деривации и изменить содержание метода по мере необходимости. Поскольку это статический метод, мы не можем. Конечно, если нам просто нужно добавить функциональность до или после старого метода, мы можем создать новый класс и называть его старым, но это просто грубо.

Интерфейс беды
Статические методы не могут быть определены через интерфейсы для логических причин. И поскольку мы не можем переопределять статические методы, статические классы бесполезны, когда нам нужно передать их своим интерфейсом. Это позволяет нам не использовать статические классы как часть шаблона стратегии. Мы можем исправить некоторые проблемы до passing delegates instead of interfaces.

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

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

параметров ползучести
Начнем с того, что мало милые и невинные статический метод может принимать один параметр. По мере роста функциональности добавляется пара новых параметров. Вскоре добавляются дополнительные параметры, которые являются необязательными, поэтому мы создаем перегрузки метода (или просто добавляем значения по умолчанию на языках, которые их поддерживают). Вскоре у нас есть метод, который принимает 10 параметров. Только первые три действительно необходимы, параметры 4-7 являются необязательными. Но если параметр 6 указан, необходимо заполнить 7-9 ... Если бы мы создали класс с единственной целью сделать то, что сделал этот статический метод, мы могли бы решить это, взяв требуемые параметры в конструктор и позволяет пользователю устанавливать необязательные значения через свойства или методы для одновременного задания нескольких взаимозависимых значений. Кроме того, если метод вырос до такого уровня сложности, он, скорее всего, должен быть в своем собственном классе.

Требуя потребителей, чтобы создать экземпляр класса без причины
Одним из наиболее распространенных аргументов, почему спрос, что потребители нашего класса создать экземпляр для вызова этого один метод, при этом не имея использовать для экземпляра после этого? Создание экземпляра класса - очень дешевая операция на большинстве языков, поэтому скорость не является проблемой. Добавление лишней строки кода для потребителя - это низкая стоимость заложить основу для гораздо более удобного решения в будущем. И, наконец, если вы хотите избежать создания экземпляров, просто создайте одноэлементную оболочку своего класса, которая позволяет легко повторное использование, хотя это и делает требование о том, чтобы ваш класс не имел гражданства. Если он не является апатридом, вы все равно можете создавать статические методы-обертки, которые обрабатывают все, сохраняя при этом все преимущества в долгосрочной перспективе. Наконец, вы также можете создать класс, который скрывает экземпляр, как если бы он был singleton: MyWrapper.Экземпляр - свойство, которое просто возвращает новый MyClass();

Только дело ситхов в абсолюте
Конечно, есть исключения из моей нелюбви статических методов. Истинные классы полезности, которые не представляют опасности для вздутия, являются отличными случаями для статических методов - например, System.Convert. Если ваш проект является одноразовым, без требований к будущему обслуживанию, общая архитектура действительно не очень важна - статическая или не статическая, на самом деле не имеет значения - скорость разработки, однако.

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

78

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

Классы, которые существуют только для их методов, должны быть оставлены статическими.

+16

-1 «Классы, которые существуют только для их методов, должны оставаться статическими». – Rookian 2011-08-13 16:00:06

+3

@Rookian, почему вы не согласны с этим? – jjnguy 2011-08-14 15:27:04

+5

примером будет шаблон репозитория. Класс содержит только методы. После вашего подхода не разрешается использовать интерфейсы. => увеличить связь – Rookian 2011-08-14 16:23:14

3

Может ли ваш класс быть статическим?

Если это так, то я бы сделал это класс «Утилиты», что я бы поставил все свои классы один-функции в.

14

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

5

Я действительно не знаю, что здесь происходит, но я бы посмотрел на его применение как метод в одном из классов, к которым принадлежат arg1, arg2 или arg3. Если вы можете семантически сказать, что один из этих классы будут владеть методом.

5

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

10

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

Я также предостерег от гигантского класса Utils, который имеет десятки несвязанных статических методов. Это может стать дезорганизованным и громоздким в спешке. Лучше иметь много классов, каждый из которых имеет мало связанных методов.

2

Я бы просто сделал все в конструкторе. как так:

new MyClass(arg1, arg2, arg3);// the constructor does everything. 

или

MyClass my_object(arg1, arg2, arg3); 
3

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

4

Я предлагаю, чтобы его трудно было ответить на основании предоставленной информации.

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

Конечно, сложно сказать, почему вам нужно создать отдельный класс только для этого метода. Является ли это типичной ситуацией класса «Утилиты», поскольку большинство из них предполагает? Или вы внедряете какой-то класс правил, чего может быть больше в будущем.

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

3

Для простых приложений и помощников internal я бы использовал статический метод. Для приложений с компонентами я люблю Managed Extensibility Framework. Вот выдержка из документа, который я пишу, чтобы описать шаблоны, которые вы найдете в моих API.

  • Услуги
    • Определяется с помощью I[ServiceName]Service интерфейса.
    • Экспортировано и импортировано по типу интерфейса.
    • Единственная реализация обеспечивается хост-приложением и потребляется внутренне и/или расширениями.
    • Методы сервисного интерфейса являются потокобезопасными.

Как надуманный пример:

public interface ISettingsService 
{ 
    string ReadSetting(string name); 

    void WriteSetting(string name, string value); 
} 

[Export] 
public class ObjectRequiringSettings 
{ 
    [Import] 
    private ISettingsService SettingsService 
    { 
     get; 
     set; 
    } 

    private void Foo() 
    { 
     if (SettingsService.ReadSetting("PerformFooAction") == bool.TrueString) 
     { 
      // whatever 
     } 
    } 
} 
0

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

Следует обратить внимание на состояние системы.

0

Возможно, вы сможете избежать ситуации вместе. Попробуйте рефакторинг, чтобы получить arg1.myMethod1(arg2, arg3). Swap arg1 с arg2 или arg3, если это имеет смысл.

Если вы не имеете контроля над классом arg1, а затем украсить его:

class Arg1Decorator 
    private final T1 arg1; 
    public Arg1Decorator(T1 arg1) { 
     this.arg1 = arg1; 
    } 
    public T myMethod(T2 arg2, T3 arg3) { 
     ... 
    } 
} 

arg1d = new Arg1Decorator(arg1) 
arg1d.myMethod(arg2, arg3) 

Аргументация, что в ООП, данные и методы обработки данных, которые связаны друг с другом. Кроме того, вы получаете все преимущества, о которых упоминал Марк.

0

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