#class #c#-4.0 #stateless
#класс #c #-4.0 #без состояния
Вопрос:
Я хотел бы знать, каковы недостатки класса без состояния (если таковые имеются)? Кто-нибудь видел реальное приложение, в котором какой-либо вариант использования требовал создания класса без состояния (пожалуйста, не приветствуйте мир)? Я думаю, что класс без состояния означает класс без каких-либо полей.
Комментарии:
1. Это странный вопрос. Какую проблему вы пытаетесь решить?
2. я знаю, что это немного абстрактно, но в настоящее время я пытаюсь понять, следует ли мне рассмотреть возможность изменения моего текущего рабочего кода для включения классов без состояния (у меня нет опыта работы с классами без состояния)… надеюсь, я немного прояснил..
3. Совсем не ясно, что вы подразумеваете под «классом без состояния». Какой язык вы используете? Вы имеете в виду классы без элементов данных или что-то еще (возможно, неизменяемые объекты)?
4. меня просят или, скорее, говорят изменить класс myclass {..} на внутренний статический класс myclass{….}
Ответ №1:
Вот реальный пример: написание плагинов для Microsoft Dynamics CRM.
В этом документе вы увидите примечание, в котором говорится: «Метод Execute подключаемого модуля должен быть записан как не имеющий состояния». И в основном то, что означает быть классом без состояния, заключается в том, что не должно быть глобальных переменных (за исключением нескольких особых случаев, в которые я не буду вдаваться, если меня не спросят).
Причина, по которой CRM требует этого от разработчиков плагинов, заключается в том, что CRM пытается повысить производительность за счет кэширования и повторного использования экземпляров классов плагинов. Способ, которым CRM выполняет свои плагины, примерно таков:
Основной поток:
YourCustomPlugin yourCustomPluginCached = new YourCustomPlugin();
затем позже:
Thread1:
yourCustomPluginCached.Execute(context1);
и Thread2:
yourCustomPluginCached.Execute(context2);
Что некоторые разработчики делают неправильно, так это то, что они создают глобальную переменную для хранения контекста, который они устанавливают в качестве первой строки в методе Execute() . Таким образом, им не нужно передавать его между всеми своими методами. Но на самом деле это огромная ошибка.
Потому что, если они это сделают, и в приведенном выше сценарии, если выполнение в thread2 начнется до завершения выполнения из thread1. Это означало бы, что context1 в thread1 будет перезаписан context2 . И теперь этот плагин будет иметь неожиданный результат. В 99% случаев, даже при неправильной разработке таким образом, проблем нет или нет заметных проблем. Но в 1% случаев это приведет к тому, что что-то пойдет не так, и разработчику будет невероятно сложно выяснить, что пошло не так, и, вероятно, никогда не произойдет при тестировании / отладке. Так что, вероятно, он будет оставаться незафиксированным в течение длительного времени.
Комментарии:
1. Вопрос задавался для реального примера. Это первый ответ, который дает его.
2. вы не возражаете, если я спрошу вас о нескольких особых случаях через несколько лет?
Ответ №2:
Я никогда не слышал «класс без состояния», но я думаю, вы имеете в виду неизменяемые объекты (очень полезное понятие!). Или, может быть, класс, в котором нет никаких полей, поэтому обычно он выглядит как просто набор чистых функций.
Комментарии:
1. да, мои поля перемещаются в метод, поэтому класс — это просто набор методов, собранных вместе
2. Тогда вы имеете в виду «статический класс»? Насколько я знаю, он есть в C #, не уверен, что в этом есть большой смысл, но да, это способ объявить кучу статических методов (которые обычно не имеют состояния).
3. я предполагаю, что …. мой вопрос остается, почему я должен выбирать один над другим или, проще говоря, что заставит меня переосмыслить свой дизайн? что это за критический фактор, который заставил бы меня перейти на класс без состояния (класс без каких-либо полей)?
4. Если вам нужна куча en.wikipedia.org/wiki/Pure_function с. Это случается не очень часто, но обычно это могут быть утилиты, помощники и т. Д.
Ответ №3:
Если под классом без состояния вы подразумеваете класс неизменяемых объектов, то недостатком является то, что операции изменения должны копировать объект, а не изменять его на месте. Это может быть дорого.
Я использую эти вещи довольно часто, в значительной степени всякий раз, когда поведение объекта определяется некоторыми входными данными, которые могут быть обработаны все сразу. Недавний пример — это статистическая языковая модель, которую я реализовал: параметры модели были полностью определены в конструкторе на основе обучающих входных данных, а затем к модели можно было запросить оценки вероятности для невидимого текста, но не изменять. Неизменность не была строго обязательной, но изменение объекта не имело смысла, поскольку не было необходимости добавлять данные позже (в этом случае большую часть вычислений все равно приходилось переделывать).
Комментарии:
1. Хм… Я не уверен, что согласен с тем, что неизменяемый объект не имеет состояния. Но я думаю, это может быть то, о чем просил ашутош.
2. Я бы не знал, что еще может быть классом без состояния, если только OP не использует один из тех языков, где для обычной функции требуется
class {}
блок и два идентификатора, чтобы назвать его.3. можете ли вы привести мне пример, когда вы начинали без класса без состояния, а затем его наличие дало вам преимущества?
4. @ashutoshraina: нет, потому что функциональное программирование заполонило мой мозг до такой степени, что я склонен создавать неизменяемые объекты, а затем добавлять мутаторы, когда они кажутся абсолютно необходимыми. Обычно это делается из соображений производительности.
Ответ №4:
Я тоже не уверен, что вы подразумеваете под этим термином, но я предполагаю, что это означает класс без полей, поскольку состояние объекта на самом деле является содержимым его полей.
Обычно вы используете этот класс как набор связанных функций — скажем, определенный Utils
класс. Обычный способ использования такого класса — сделать его метод статическим, поэтому на самом деле вам не нужно создавать экземпляр класса.
Единственная причина, по которой я могу придумать, чтобы на самом деле создать такой объект без состояния, — это если вы хотите, чтобы фактическая функциональность определялась во время выполнения. Итак, если у вас есть UtilsBase
класс, который предлагает множество виртуальных методов и UtilsDerived
который переопределяет некоторые из методов, вы можете передать любому, кому нужно использовать утилиты, ссылку на UtilsBase
и создать фактический объект utils во время выполнения, в соответствии с конкретными потребностями.
Ответ №5:
Немного поздно, но вот моя доля. Я уверен, что плакат имел в виду stateless object
. Пожалуйста, люди, не делайте это так драматично.
Давайте перейдем к делу. Некоторые комментаторы спрашивали о. static
Когда в классе используется static, который следует использовать экономно, все члены, содержащие ключевое слово static, теперь принадлежат классу, а не объекту. Они являются частью класса. Например:
Объявление Person
класса с вызываемым static
свойством Name
не имеет смысла
public class Person
{
public **static** string Name { get; set; }
}
- кстати, другим словом для статического является «Общий», который используется в VB.NET .
Если мы однажды зададим имя для Person, то это имя будет использоваться повсеместно, потому что оно принадлежит не объекту, а самому классу. В реальном мире вы бы не стали называть всех людей «Jhon» или всех своих клиентов «Customer1». У каждого будет свое имя, фамилия, телефон, адрес и т.д. В тот момент, когда мы устанавливаем эти свойства, этот объект становится с сохранением состояния, а не без состояния. У него есть имя, адрес и т.д. Свойства объекта, определенного в классе, делают его с сохранением состояния.
Здесь свойство Name принадлежит классу, а не части объекта:
Person.Name="Fili" //You would not call every person Fili in your application.
Давайте переопределим класс Person, удалив ключевое слово static:
public class Person
{
public string Name { get; set; }
}
В приведенном ниже примере объект отслеживает состояние. У него есть состояние, ему присвоено имя «Jhon», которое можно изменить позже. Человек может изменить свое имя на Джимми, например. Как только это будет сделано, состояние этого объекта изменится с Jhon на Jimmy.
//From
Person person1 = new Person {
Name = "Jhon";
}
//to
person1.Name = "Jimmy"
Объект ‘person1’ по-прежнему является тем же объектом, но его состояние изменилось. Это уже не то же самое. У него другое имя.
Итак, person1 имел состояние до определенного момента времени, но затем его состояние было изменено. Теперь он находится в другом состоянии.
Теперь создание нового person — это нечто новое, не имеющее ничего общего с person1. Person2 имеет свое собственное состояние.
Person person2 = new Person {
Name = "Imir";
}
Использование статического класса: Person.Name="Fili"
у него есть состояние, но оно принадлежит классу и используется повсеместно.
Таким образом, объект без состояния будет таким, который ничего не нужно изменять, не содержит значения. Вы создадите человека без имени? Вы бы создали объект customer, который не существует? Нет, конечно, нет. В тот момент, когда вы называете пользователя или клиента, у них есть состояние. Они существуют и могут изменять свое состояние.
Возьмем пример самолета. Например, когда вы удаляете его, вы добавляете свойство Status.
public class Airplane {
public string Status {get;set;}
}
var plane1 = new Airplane{ Status="Flying"};
Итак, возникает вопрос: каково состояние (статус) плоскости в этот момент?
Можно было бы ответить: он «летит». Если вы измените состояние на «налогообложение», то его состояние будет «налогооблагаемым», или оно будет «стационарным» и т. Д.
Ответ №6:
В классе без состояния все члены поля должны иметь тип только для чтения. Хотя в c # нет таких функций, которые будут проверять отсутствие состояния во время компиляции, например:
public readonly class MyReadonlyClass
{
public readonly double X {get;set;}
public readonly double Y {get;set;}
public readonly double Z {get;set;}
public MyReadonlyClass(double x_,double y_,double z_)
{
X=x_;Y=y_;Z=z_;
}
}
public readonly static class MyStaticReadonlyClass
{
public readonly static double X {get;set;}
public readonly static double Y {get;set;}
public readonly static double Z {get;set;}
static MyStaticReadonlyClass(double x_,double y_,double z_)
{
X=x_;Y=y_;Z=z_;
}
}
Ответ №7:
Состояние без состояния — это то, что не должно сохранять свое состояние, или, другими словами, мы можем сказать, что каждый раз, когда мы используем какую-либо функциональность или член этого класса, ранее использованные / установленные переменные не должны влиять на следующее использование этого класса / функциональности.
Рассмотрим следующий фрагмент кода (игнорируйте стандарты)-
class Maths {
int radius;
public void setRadius(int r) {
this.radius = r;
}
public float getCircleArea() {
return (float) (3.14 * radius * radius);
}
}
public class Geometry {
public static void main(String[] args) {
Maths m = new Maths();
m.setRadius(14);
System.out.println(m.getCircleArea());
}
}
если какой-либо другой запущенный поток изменит значение radius в классе Maths, то getCircleArea() даст нам другие результаты, потому что состояние переменной ‘radius’ может быть изменено, поскольку это глобальная переменная. Эта проблема возникает в основном в веб-приложении, где мы используем bean-контейнеры. Большинство компонентов являются одноэлементными и имеют только одну копию. Если мы используем глобальные переменные, то есть вероятность, что значение глобальной переменной изменится.
Чтобы создать класс без состояния, попробуйте использовать локальную переменную, чтобы область действия переменной была ограничена. Примером приведенного выше getCircleArea() будет.
public float getCircleArea(int radius) {
return (float) (3.14 * radius * radius);
}