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 {@Beforepublic void before() {// 每次@Test前执行.Turnstile t = new Turnstile();t.reset();}@Testpublic void whenInit() {Turnstile t = new Turnstile();Assert.assertTrue(t.locked());}@Testpublic void whenCoin() {Turnstile t = new Turnstile();t.coin();Turnstile t1 = new Turnstile();Assert.assertTrue(!t1.locked());Assert.assertEquals(1, t1.coins());}@Testpublic 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());}@Testpublic 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());}@Testpublic void whenPass() {Turnstile t = new Turnstile();t.pass();Turnstile t1 = new Turnstile();Assert.assertTrue(t1.alarm());Assert.assertTrue(t1.locked());}@Testpublic 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());}@Testpublic 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());}
}