我想知道无状态类(如果有的话)的缺点是什么? 有没有人看到一个真实的应用程序,其中一些用例强制创建一个无状态类(请问你好世界)? 我认为无国籍阶级意味着没有任何领域的阶级。
答案 0 :(得分:4)
这是一个真实世界的例子: Writing plugins for Microsoft Dynamics CRM
在该文档中,您将看到一条说明:“插件的Execute方法应该写为无状态”。 基本上,无状态类意味着应该没有全局变量(除少数特殊情况外,除非被问到,否则我不会进入)。
CRM对插件开发人员强制的原因是因为CRM试图通过缓存和重新使用插件类的实例来提高性能。 CRM执行其插件的方式大致如下:
主线程:
YourCustomPlugin yourCustomPluginCached = new YourCustomPlugin();
然后呢: 线程1:
yourCustomPluginCached.Execute(context1);
和Thread2:
yourCustomPluginCached.Execute(context2);
一些开发人员错误的是他们将创建一个全局变量来存储Context,他们将其设置为Execute()方法的第一行。这样他们就不必在所有方法之间传递它。但这实际上是一个巨大的错误。 因为如果他们这样做,并且在上面的场景中,如果thread2中的执行在thread1的执行完成之前开始。这意味着thread1中的context1将被context2覆盖。现在该插件会有一些意想不到的结果。在99%的情况下,即使以这种方式不正确地开发,也没有问题或没有明显的问题。但是在1%的情况下,它会导致出现问题,并且开发人员很难找出问题所在,并且在测试/调试时可能永远不会发生。所以很长一段时间它可能会不固定。
答案 1 :(得分:1)
如果stateless class表示一类不可变对象,则缺点是变异操作需要复制对象而不是就地更改它。这可能很贵。
我经常使用这些东西,几乎每当一个对象的行为由一些可以一次处理的输入确定时。最近的一个例子是我实现的statistical language model:模型参数完全在构造函数中基于训练输入确定,然后可以查询模型以查看未见文本的概率,但不进行修改。不变性并不是严格规定的,但修改对象没有意义,因为以后不需要添加数据(在这种情况下,大部分计算都必须重做)。
答案 2 :(得分:1)
我从未听过“无国籍级”,但我认为你的意思是不可变对象(非常有用的概念!)。 或者也许是一个没有任何字段的类,所以通常看起来只是一堆纯函数。
答案 3 :(得分:1)
我也不确定你的意思是什么,但我认为它意味着没有字段的类,因为对象的状态实际上是其字段的内容。
现在,通常你会使用这种类作为相关函数的集合 - 比如某个Utils
类。使用这种类的常用方法是将其方法设置为静态,因此您实际上不必创建该类的实例。
我能想到实际创建这样一个无状态对象的唯一原因是你是否希望在运行时确定实际的功能。所以,如果你有一个UtilsBase
类,它提供了一堆虚拟方法,并且UtilsDerived
覆盖了一些方法,那么你可以将需要使用utils的人传递给UtilsBase
,并根据具体需要在运行时创建实际的utils对象。
答案 4 :(得分:0)
在无状态类中,所有字段成员都应该是只读类型。虽然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_;
}
}
答案 5 :(得分:0)
无状态是不应该保留其状态的东西,换句话说,我们可以说每次我们使用该类的任何功能或成员时,之前使用的/设置变量不应该影响该类/功能的下一次使用。
请考虑以下代码段(忽略标准) -
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());
}
}
如果某个其他正在运行的线程在类Maths中更改了radius的值,那么getCircleArea()会给我们不同的结果,因为变量' radius'可以改变,因为它是一个全局变量。此问题主要发生在我们使用bean容器的Web应用程序中。大多数bean都是Singleton,只有一个副本。如果我们使用全局变量,那么全局变量的值可能会发生变化。
要创建无状态类,请尝试使用局部变量,以便限制变量的范围。 上面的getCircleArea()示例将是。
public float getCircleArea(int radius) {
return (float) (3.14 * radius * radius);
}