我相信有不少人还不明白有状态和无状态(Stateful and Stateless)的概念,那么我们今天就来谈谈有状态和无状态,一方面不断总结提高自我,另一方面兼扫盲。
基本概念:
有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。 无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象.不能保存数据,是不变类,是线程安全的。
有状态的噩梦
在使用基于有状态类的API的时候,我们也许有机会调用很多跟状态有关的公共方法,这些调用方式到底符不符合时机这是一个很大的问题(我的代码写得足够的防御也最多就是抛异常罢了)。API的调用方需要做的事,1,忍受和处理异常 2,学习状态类工作机制。没办法 你要写一个基于状态类的API用户就得做那么多事,下面就是一个状态类的例子:
public abstract class Stateful {
public static Stateful create(String name) {
return createImpl(name);
}
public abstract void start(int totalAmount);
public abstract void progress(int howMuch);
public abstract void finish();
// FINISH: progress.api
Stateful() {
}
private static Stateful createImpl(String name) {
return new Impl(name);
}
private static final class Impl extends Stateful {
private final String name;
private int total = -1;
private int current;
public Impl(String name) {
this.name = name;
}
@Override
public void start(int totalAmount) {
total = totalAmount;
}
@Override
public void progress(int howMuch) {
if (total == -1) {
throw new IllegalStateException("Call start first!");
}
current = howMuch;
}
@Override
public void finish() {
total = -1;
current = 0;
}
}
}
试想如果你一下面这种顺序调用API
Stateful p = Stateful.create("bad idea");
p.progress(10);
p.finish();
p.progress(10);
p.finish();
你得到的会是一个RuntimeException,原因是你忘记启动它了,从常识来讲我们的确应该先启动它才能有进度。但是这只是一个简单的例子 ,我们不能保证所有的状态机业务都跟这个一样简单用常识都能排错!久而久之这样的API会报废掉,因为它要的太多了!
”无状态“的API
当我们把上述的状态机方法适当的归类,一个处于配置 另外一个属于过程,用配置去实例化过程。
public abstract class Stateless {
// BEGIN: progress.phases
public static Stateless create(String name) {
return createImpl(name);
}
public abstract InProgress start(int totalAmount);
public abstract class InProgress {
public abstract void progress(int howMuch);
public abstract void finish();
// FINISH: progress.phases
InProgress() {
}
}
private static Stateless createImpl(String name) {
return new Impl(name);
}
private static final class Impl extends Stateless {
private final String name;
public Impl(String name) {
this.name = name;
}
@Override
public InProgress start(int totalAmount) {
return new InImpl(totalAmount);
}
private class InImpl extends InProgress {
private final int total;
private int current;
public InImpl(int total) {
this.total = total;
}
@Override
public void progress(int howMuch) {
current = howMuch;
}
@Override
public void finish() {
current = total;
}
}
}
}
// BEGIN: progress.phases
public static Stateless create(String name) {
return createImpl(name);
}
public abstract InProgress start(int totalAmount);
public abstract class InProgress {
public abstract void progress(int howMuch);
public abstract void finish();
// FINISH: progress.phases
InProgress() {
}
}
private static Stateless createImpl(String name) {
return new Impl(name);
}
private static final class Impl extends Stateless {
private final String name;
public Impl(String name) {
this.name = name;
}
@Override
public InProgress start(int totalAmount) {
return new InImpl(totalAmount);
}
private class InImpl extends InProgress {
private final int total;
private int current;
public InImpl(int total) {
this.total = total;
}
@Override
public void progress(int howMuch) {
current = howMuch;
}
@Override
public void finish() {
current = total;
}
}
}
}
这样就解决了过程的初始化问题:
Stateless p = Stateless.create("Good idea!");
InProgress progress = p.start(10);
// without calling start(), there is no way to call progress() method
progress.progress(10);
progress.finish();
InProgress progress = p.start(10);
// without calling start(), there is no way to call progress() method
progress.progress(10);
progress.finish();