State 模式


您現在正設計一個交通號誌程式,假設目前只有紅、綠、黃三個燈號,您也許會這麼設計:
class TrafficLight {
private enum State {RED, GREEN, YELLOW}
private State state = State.RED;
void change() {
switch(state) {
case RED:
System.out.println("紅燈");
sleep(5000);
state = State.GREEN;
break;
case GREEN:
System.out.println("綠燈");
sleep(5000);
state = State.YELLOW;
break;
case YELLOW:
System.out.println("黃燈");
sleep(1000);
state = State.RED;
}
}
private void sleep(int second) {
try {
Thread.sleep(second);
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}

這 是以結構化的方式來設計,優點是簡單直覺,缺點是若狀態增多(也許增加多個時相燈號)時,整個流程會變得冗長,如果狀態變化非線性結構(如紅--> 綠-->黃),可能有兩個或多個方向的狀態變化時,結構化的設計方式,將會增加更多層次的判斷,造成程式碼閱讀、管理的麻煩。

可以考慮讓每個狀態各自成為一個物件,負責自己該狀態的服務,並提供切 換狀態的方法
interface State {
void change(TrafficLight light);
}

abstract class Light implements State {
public abstract void change(TrafficLight light);
protected void sleep(int second) {
try {
Thread.sleep(second);
}
catch(InterruptedException e) {
e.printStackTrace();
}
}
}

class Red extends Light {
public void change(TrafficLight light) {
System.out.println("紅燈");
sleep(5000);
light.set(new Green()); // 如果考慮彈性調整狀態,可以不用寫死狀態物件設定
}
}

class Green extends Light {
public void change(TrafficLight light) {
System.out.println("綠燈");
sleep(5000);
light.set(new Yellow());
}
}

class Yellow extends Light {
public void change(TrafficLight light) {
System.out.println("黃燈");
sleep(1000);
light.set(new Red());
}
}

class TrafficLight {
private State current = new Red();
void set(State state) {
this.current = state;
}
void change() {
current.change(this);
}
}

public class Main {
public static void main(String[] args) {
TrafficLight trafficLight = new TrafficLight();
while(true) {
trafficLight.change();
}
}
}

當狀態的轉換有方向性時,這樣的設計就很有彈性,正如範例所示的,對於單一方向性的狀態變化,可以提供一個change()方法來轉換狀態,如果狀態有前 後切換,則可以提供back()、forward()方法來切換,依此類推...

以Python來實現這個範例:
import time

class Red:
def change(self, light):
print("紅燈")
time.sleep(5)
light.set(Green())

class Green:
def change(self, light):
print("綠燈")
time.sleep(5)
light.set(Yellow())

class Yellow:
def change(self, light):
print("黃燈")
time.sleep(1)
light.set(Red())

class TrafficLight:
def __init__(self):
self.current = Red()

def set(self, state):
self.current = state

def change(self):
self.current.change(self)

trafficLight = TrafficLight()
while True:
trafficLight.change()

以UML表示State模式結構: