Singleton 和 Monostate 模式
怎样才能使得两个实例表现得像一个对象呢?很简单,只要把所有的变量都变成静态变量即可。
public class Monostate {
private static int itsX = 0;
public Monostate() {
}
public void setX(final int x) {
itsX = x;
}
public int getX() {
return itsX;
}
}
实现地铁十字转门的简单的有限状态机。十字转门开始时处于Locked 状态。如果投入一枚硬币,它就迁移到Unlocked 状态,开启转门,复位可能出现的任何告警状态,并把硬币放到收集箱柜中。如果此时乘客通过了转门,转门就迁移回Locked 状态并把门锁上。
实现类
public class Turnstile {
/**
* 是否已锁.
*/
private static boolean isLocked = true;
/**
* 是否报警中.
*/
private static boolean isAlarming = false;
/**
* 硬币数.
*/
private static int itsCoins = 0;
/**
* 退款数.
*/
private static int itsRefunds = 0;
protected static final Turnstile LOCKED = new Locked();
protected static final Turnstile UNLOCKED = new Unlocked();
protected static Turnstile itsState = LOCKED;
public void reset() {
lock(true);
alarm(false);
itsCoins = 0;
itsRefunds = 0;
itsState = LOCKED;
}
public boolean locked() {
return isLocked;
}
public boolean alarm() {
return isAlarming;
}
/**
* 投币.
*/
public void coin() {
itsState.coin();
}
/**
* 通过.
*/
public void pass() {
itsState.pass();
}
/**
* 设置锁住.
* @param shouldLock
*/
protected void lock(boolean shouldLock) {
isLocked = shouldLock;
}
/**
* 设置报警.
* @param shouldAlarm
*/
protected void alarm(boolean shouldAlarm) {
isAlarming = shouldAlarm;
}
/**
* 获取投币数.
* @return
*/
public int coins() {
return itsCoins;
}
/**
* 获取退款数.
* @return
*/
public int refunds() {
return itsRefunds;
}
/**
* 存钱.
*/
public void deposit() {
itsCoins++;
}
/**
* 退款.
*/
public void refund() {
itsRefunds++;
}
static class Locked extends Turnstile {
public void coin() {
Turnstile.itsState = UNLOCKED;
lock(false);
alarm(false);
deposit();
}
public void pass() {
alarm(true);
}
}
static class Unlocked extends Turnstile {
public void coin() {
refund();
}
public void pass() {
lock(true);
itsState = LOCKED;
}
}
}
测试类
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class TurnstileTest {
@Before
public void before() {
// 每次@Test前执行.
Turnstile t = new Turnstile();
t.reset();
}
@Test
public void whenInit() {
Turnstile t = new Turnstile();
Assert.assertTrue(t.locked());
}
@Test
public void whenCoin() {
Turnstile t = new Turnstile();
t.coin();
Turnstile t1 = new Turnstile();
Assert.assertTrue(!t1.locked());
Assert.assertEquals(1, t1.coins());
}
@Test
public void whenCoinAndPass() {
Turnstile t = new Turnstile();
t.coin();
t.pass();
Turnstile t1 = new Turnstile();
Assert.assertTrue(t1.locked());
Assert.assertTrue(!t1.alarm());
Assert.assertEquals(1, t1.coins());
}
@Test
public void whenTowCoins() {
Turnstile t = new Turnstile();
t.coin();
t.coin();
Turnstile t1 = new Turnstile();
Assert.assertTrue(!t1.locked());
Assert.assertEquals(1, t1.coins());
Assert.assertEquals(1, t1.refunds());
Assert.assertTrue(!t1.alarm());
}
@Test
public void whenPass() {
Turnstile t = new Turnstile();
t.pass();
Turnstile t1 = new Turnstile();
Assert.assertTrue(t1.alarm());
Assert.assertTrue(t1.locked());
}
@Test
public void whenCancelAlarm() {
Turnstile t = new Turnstile();
t.pass();
t.coin();
Turnstile t1 = new Turnstile();
Assert.assertTrue(!t1.alarm());
Assert.assertTrue(!t1.locked());
Assert.assertEquals(1, t1.coins());
Assert.assertEquals(0, t1.refunds());
}
@Test
public void whenTwoOperations() {
Turnstile t = new Turnstile();
t.coin();
t.pass();
t.coin();
Assert.assertTrue(!t.locked());
Assert.assertEquals(2, t.coins());
t.pass();
Assert.assertTrue(t.locked());
}
}