トランザクションのステータス(ステータス・モード)

15795 ワード

【0】README
0.1)本明細書の一部のテキスト記述は「head first設計モード」から転載し、学習を目的とする トランザクションのステータス(ステータスモード)の基礎知識;
【1】適用シーン1
1.1)成都市の各高校内の米源自動販売機を覚えていますか.販売機の主なメーカーは、CPUを機械に入れるだけで販売台数を上げることができることを発見した.そこで、自動販売機の状態図を提供してくれました.javaで実現し、コードが弾力性に富んで拡張しやすいことを望んでいます(以下、米源キャンディ販売機を例にステータス図を示します).
1.2)具体的な実現(for downloading,please visit https://github.com/pacosonTang/HeadFirstDesignPattern/tree/master/state_pattern_10/chapter10)
  • step 1)米源販売機
  • を実現
  • public class CandyMachine {
    	private final static int SOLD_OUT = 0; //     
    	private final static int NO_QUARTER = 1; //     ,QUARTER==25  == 
    	private final static int HAS_QUARTER = 2; //     
    	private final static int SOLD = 3; //     
    	private int state = SOLD_OUT;
    	private int count = 0;
    	
    	public CandyMachine(int count) {
    		this.count = count;
    		if(count > 0) {
    			this.state = NO_QUARTER;
    		}
    	}
    	
    	public void insertQuarter() { // client    
    		if(state == HAS_QUARTER) {
    			System.out.println("you can't insert another quarter.");
    		} else if(state == NO_QUARTER) {
    			System.out.println("you insert a quarter.");
    			state = HAS_QUARTER;
    		} else if(state == SOLD_OUT) {
    			System.out.println("you can't insert a quarter for the machine is sold out.");
    		} else if(state == SOLD) {
    			System.out.println("please wait, we're already gibing you a candy.");
    		}
    	}
    	
    	public void ejectQuarter() { // client    
    		if(state == HAS_QUARTER) {
    			System.out.println("quarter returned.");
    			state = NO_QUARTER;
    		} else if(state == NO_QUARTER) {
    			System.out.println("you haven't inserted a quarter.");
    		} else if(state == SOLD_OUT) {
    			System.out.println("you can't eject for you haven't inserted a quarter yet.");
    		} else if(state == SOLD) {
    			System.out.println("sorry, you already trune the crank.");
    		}
    	}
    	
    	public void turnCrank() { // client      
    		if(state == HAS_QUARTER) {
    			System.out.println("you turned, please wait....");
    			state = SOLD;
    			dispense();
    		} else if(state == NO_QUARTER) {
    			System.out.println("you turned but there is no quarter.");
    		} else if(state == SOLD_OUT) {
    			System.out.println("you truned but there's no candy.");
    		} else if(state == SOLD) {
    			System.out.println("turning twice doesn't get you another candy.");
    		}
    	}
    	
    	private void dispense() { //     
    		if(state == HAS_QUARTER) {
    			System.out.println("no candy dispensed.");
    		} else if(state == NO_QUARTER) {
    			System.out.println("you need to insert a quarter first.");
    		} else if(state == SOLD_OUT) {
    			System.out.println("no candy dispensed.");
    		} else if(state == SOLD) {
    			System.out.println("a candy comes rolling out the slot.");
    			count--;
    			if(count == 0) {
    				System.out.println("Oops, there's no candy.");
    				state = SOLD_OUT;
    			} else {
    				state = NO_QUARTER;
    			}
    		}
    	}
    
    	@Override
    	public String toString() {
    		String state_str = null;
    		
    		switch (state) {
    		case SOLD_OUT: state_str = "SOLD_OUT"; break;
    		case SOLD: state_str = "SOLD"; break;
    		case NO_QUARTER: state_str = "NO_QUARTER"; break;
    		case HAS_QUARTER: state_str = "HAS_QUARTER"; break;
    		}
    		return "=== I own " + count + " candies, and stay in " + state_str + " state. ===";
    	}
    }
  • step 2)試験用例
  • public class CandyMachineTest {
    	public static void main(String[] args) {
    		CandyMachine cm = new CandyMachine(5);
    		System.out.println(cm);
    		
    		System.out.println("====== 1st test: ======");
    		cm.insertQuarter();
    		cm.turnCrank();
    		System.out.println(cm);
    		
    		System.out.println("====== 2nd test: ======");
    		cm.insertQuarter();
    		cm.ejectQuarter();//       
    		cm.ejectQuarter();//          
    		
    		System.out.println("====== 3rd test: ======");
    		cm.insertQuarter();
    		cm.ejectQuarter();
    		cm.turnCrank();//      ,       
    		System.out.println(cm);
    	}
    }
  • step 3)印刷結果
  • === I own 5 candies, and stay in NO_QUARTER state. ===
    ====== 1st test: ======
    you insert a quarter.
    you turned, please wait....
    a candy comes rolling out the slot.
    === I own 4 candies, and stay in NO_QUARTER state. ===
    ====== 2nd test: ======
    you insert a quarter.
    quarter returned.
    you haven't inserted a quarter.
    ====== 3rd test: ======
    you insert a quarter.
    quarter returned.
    you turned but there is no quarter.
    === I own 4 candies, and stay in NO_QUARTER state. ===
  • 【2】適用シーン2(クランクが回転すると、10%の確率で落ちるキャンディが2つ、つまり10%の確率で1つずつ買う)
    2.1)新たな需要の下での米源販売機の実現 (for downloading, please visit  https://github.com/pacosonTang/HeadFirstDesignPattern/tree/master/state_pattern_10/chapter10_1)
    Step 1)は、販売機の各動作に対応する方法がある状態インタフェース(State)を定義する.
    public abstract class State {
    	protected String name;
    	public abstract void insertQuarter();
    	public abstract void ejectQuarter();
    	public abstract void trunCrank();
    	public abstract void dispense();
    	
    	public String getName() {
    		return name;
    	}
    }
  • step 2)この状態インタフェースのサブクラスを作成し、販売機の対応する方法を実現する.
  • //     
    public class SoldOutState extends State {
    	CandyMachine machine;
    	
    	public SoldOutState(CandyMachine machine) {
    		super.name = "SoldOutState";
    		this.machine = machine;
    	}
    
    	@Override
    	public void insertQuarter() {
    		System.out.println("you can't insert a quarter for there's no candies.");		
    	}
    
    	@Override
    	public void ejectQuarter() {
    		System.out.println("you have not inserted a quarter.");
    	}
    
    	@Override
    	public void trunCrank() {
    		System.out.println("you turned but there is no quarter.");
    	}
    
    	@Override
    	public void dispense() {
    		System.out.println("you need to insert a quarter first.");		
    	}
    
    }
    public class NoQuarterState extends State {
    	CandyMachine machine;
    	
    	public NoQuarterState(CandyMachine machine) {
    		super.name = "NoQuarterState";
    		this.machine = machine;
    	}
    
    	@Override
    	public void insertQuarter() {
    		System.out.println("you insert a quatter.");
    		machine.setState(machine.getHasQuarterState());
    	}
    
    	@Override
    	public void ejectQuarter() {
    		if(machine.getState() == machine.getHasQuarterState()) {
    			System.out.println("returned a quarter.");
    			machine.setState(machine.getNoQuarterState());
    		} else {
    			System.out.println("you have not inserted a quarter.");
    		}
    	}
    
    	@Override
    	public void trunCrank() {
    		System.out.println("you turned but there is no quarter.");
    	}
    
    	@Override
    	public void dispense() {
    		System.out.println("you need to insert a quarter first.");		
    	}
    }
    //     
    public class HasQuarterState extends State {
    	Random random = new Random();
    	CandyMachine machine;
    	
    	public HasQuarterState(CandyMachine machine) {
    		super.name = "HasQuarterState"; 
    		this.machine = machine;
    	}
    
    	@Override
    	public void insertQuarter() {
    		System.out.println("you can't insert another quarter.");
    	}
    
    	@Override
    	public void ejectQuarter() { // client    
    		System.out.println("quarter returned.");
    		machine.setState(machine.getNoQuarterState());
    	}
    
    	@Override
    	public void trunCrank() { //      ,         
    		System.out.println("you turned , please waiting......");
    		int winner = random.nextInt(5);
    		System.out.println("
    random winner == " + winner); if(winner == 2 && machine.getCount() > 1) { machine.setState(machine.getWinnerState()); } else { machine.setState(machine.getSoldState()); } } @Override public void dispense() { System.out.println("no candies dispensed."); } }
    //     
    public class SoldState extends State {
    	CandyMachine machine;
    	
    	
    	public SoldState(CandyMachine machine) {
    		super.name = "SoldState";
    		this.machine = machine;
    	}
    
    	@Override
    	public void insertQuarter() {		
    		System.out.println("please wait, we're already giving you a candy.");		
    	}
    
    	@Override
    	public void ejectQuarter() {
    		System.out.println("sorry, you've already turned the crank.");
    	}
    
    	@Override
    	public void trunCrank() {
    		System.out.println("turning twice doesn't get you another candy.");
    	}
    
    	@Override
    	public void dispense() {
    		machine.releaseBall();
    		if(machine.getCount() > 0) {
    			machine.setState(machine.getNoQuarterState());
    		} else {
    			machine.setState(machine.getSoldOutState());
    		}
    	}
    }
  • //     
    public class WinnerState extends State {
    	CandyMachine machine;
    	
    	public WinnerState(CandyMachine machine) {
    		this.machine = machine;
    	}
    
    	@Override
    	public void insertQuarter() {
    		System.out.println("error.");
    	}
    
    	@Override
    	public void ejectQuarter() { // client    
    		System.out.println("error.");
    	}
    
    	@Override
    	public void trunCrank() {
    		System.out.println("error.");
    	}
    
    	@Override
    	public void dispense() {
    		System.out.println("you're a winner. you get 2 candies for your quarter.");
    		machine.releaseBall();
    		if(machine.getCount() == 0) {
    			machine.setState(machine.getSoldOutState());
    		} else {
    			machine.releaseBall();
    			if(machine.getCount() > 0) {
    				machine.setState(machine.getNoQuarterState());
    			} else {
    				System.out.println("Oops, out of candies.");
    				machine.setState(machine.getSoldOutState());
    			}
    		}
    	}
    }
  • step 3)動作を状態類(構造米源キャンディ販売機)に委託する.
  • public class CandyMachine {
    	private State winnerState; //    
    	private State soldOutState; //     
    	private State noQuarterState; //     ,QUARTER==25  == 
    	private State hasQuarterState; //     
    	private State soldState; //     
    	private State state;
    	private int count = 0;
    	
    	public CandyMachine(int count) {
    		soldOutState = new SoldOutState(this);
    		soldState = new SoldState(this);
    		hasQuarterState = new HasQuarterState(this);
    		noQuarterState = new NoQuarterState(this);
    		winnerState = new WinnerState(this);
    		state = soldOutState;
    		
    		this.count = count;
    		if(count > 0) {
    			state = noQuarterState;
    		}
    	}
    	
    	public void insertQuarter() { // client    
    		state.insertQuarter();
    	}
    	
    	public void ejectQuarter() { // client    
    		state.ejectQuarter();
    	}
    	
    	public void turnCrank() { // client      
    		state.trunCrank();
    		state.dispense();
    	}
    	
    	public void releaseBall() { //     
    		System.out.println("a candy comes rolling out the slot....");
    		if(count != 0) {
    			count--;
    		}
    	}
    	
    	public State getState() {
    		return state;
    	}
    
    	public void setState(State state) {
    		this.state = state;
    	}
    	
    	public State getSoldOutState() {
    		return soldOutState;
    	}
    
    	public void setSoldOutState(State soldOutState) {
    		this.soldOutState = soldOutState;
    	}
    
    	public State getSoldState() {
    		return soldState;
    	}
    
    	public void setSoldState(State soldState) {
    		this.soldState = soldState;
    	}
    
    	public State getHasQuarterState() {
    		return hasQuarterState;
    	}
    
    	public void setHasQuarterState(State hasQuarterState) {
    		this.hasQuarterState = hasQuarterState;
    	}
    
    	public State getNoQuarterState() {
    		return noQuarterState;
    	}
    
    	public void setNoQuarterState(State noQuarterState) {
    		this.noQuarterState = noQuarterState;
    	}
    
    	public int getCount() {
    		return count;
    	}
    
    	public void setCount(int count) {
    		this.count = count;
    	}
    	public State getWinnerState() {
    		return winnerState;
    	}
    
    	public void setWinnerState(State winner) {
    		this.winnerState = winner;
    	}	
    	
    	@Override  
        public String toString() {  
            String state_str = null;  
              
            switch (state.getName()) {  
            case "SoldOutState": state_str = "SOLD_OUT"; break;  
            case "SoldState": state_str = "SOLD"; break;  
            case "NoQuarterState": state_str = "NO_QUARTER"; break;  
            case "HasQuarterState": state_str = "HAS_QUARTER"; break;  
            }  
            return "=== I own " + count + " candies, and stay in " + state_str + " state. ===";  
        }  
    }
    step 4)試験例
  • public class CandyMachineTest {
    	public static void main(String[] args) {
    		CandyMachine cm = new CandyMachine(50);
    		System.out.println(cm);
    		
    		System.out.println("====== init state ======");
    		System.out.println(cm);
    		
    		//      
    		cm.insertQuarter();
    		cm.turnCrank();
    		System.out.println(cm);
    				
    		//      
    		cm.turnCrank();
    		System.out.println(cm);
    		
    		//  3   :             
    		cm.ejectQuarter();
    		System.out.println(cm);
    		
    		System.out.println("

    ====== ( ) ==2 ======"); for (int i = 0; i < 5; i++) { cm.insertQuarter(); cm.turnCrank(); System.out.println(cm); } } }
  • step 5)印刷結果
  • === I own 50 candies, and stay in NO_QUARTER state. ===
    ====== init state ======
    === I own 50 candies, and stay in NO_QUARTER state. ===
    you insert a quatter.
    you turned , please waiting......
    
    random winner == 0
    a candy comes rolling out the slot....
    === I own 49 candies, and stay in NO_QUARTER state. ===
    you turned but there is no quarter.
    you need to insert a quarter first.
    === I own 49 candies, and stay in NO_QUARTER state. ===
    you have not inserted a quarter.
    === I own 49 candies, and stay in NO_QUARTER state. ===
    
    
     ======         (  ,      ,        20%,  <span style="font-family: Arial, Helvetica, sans-serif;">   ==2    </span><span style="font-family: Arial, Helvetica, sans-serif;">) ======</span>
    you insert a quatter.
    you turned , please waiting......
    
    random winner == 2
    you're a winner. you get 2 candies for your quarter.
    a candy comes rolling out the slot....
    a candy comes rolling out the slot....
    === I own 47 candies, and stay in NO_QUARTER state. ===
    you insert a quatter.
    you turned , please waiting......
    
    random winner == 4
    a candy comes rolling out the slot....
    === I own 46 candies, and stay in NO_QUARTER state. ===
    you insert a quatter.
    you turned , please waiting......
    
    random winner == 4
    a candy comes rolling out the slot....
    === I own 45 candies, and stay in NO_QUARTER state. ===
    you insert a quatter.
    you turned , please waiting......
    
    random winner == 2
    you're a winner. you get 2 candies for your quarter.
    a candy comes rolling out the slot....
    a candy comes rolling out the slot....
    === I own 43 candies, and stay in NO_QUARTER state. ===
    you insert a quatter.
    you turned , please waiting......
    
    random winner == 0
    a candy comes rolling out the slot....
    === I own 42 candies, and stay in NO_QUARTER state. ===
    
  • 【3】状態パターンの紹介
    1)基本的な常識:戦略モードと状態モードは双子で、生まれた時に別れた.
    2)ポリシー・モードとステータス・モード:ポリシー・モードは、互換性のあるアルゴリズムをめぐって成功したビジネスを作成する.ステータスモードは、オブジェクトの内部ステータスを変更することによって、オブジェクトが自分の動作を制御するのに役立ちます.
    3)状態モード定義:状態モードは、オブジェクトが内部状態が変化したときにその動作を変更することを可能にし、オブジェクトがクラスを変更したように見える.
    4)このモードは状態を独立したクラスにカプセル化し,現在の状態を表すクラスに動作を依頼するため,動作はコンテンツ部の状態によって変化することを知っている.
    【4】ステータスモードとポリシーモードの違い
    4.1)状態モード:我々は一連の行為を状態オブジェクトにカプセル化し、contextの行為はいつでもそれらの状態オブジェクトの1つに委託することができる.時間が経つにつれて、現在の状態は状態オブジェクトの集合の中で泳いで変化し、context内部の状態を反映するため、contextの行為も変化する.
    4.2)ポリシーパターン:お客様は通常、Contextが結合するポリシーオブジェクトを自発的に指定します.現在、ポリシー・モードは、実行時にポリシーを変更できる柔軟性を備えています.しかし、contextオブジェクトの場合、通常は最も適切なポリシーオブジェクトが1つしかありません.
    4.3)Conclusion:
  • C 1)一般的に,戦略モデルは継承を除いた弾性代替案と考えられる.継承を使用してクラスの動作を定義すると、この動作に閉じ込められ、彼を修正するのも難しいです.戦略モードがあれば、異なるオブジェクトを組み合わせることで行動を変えることができます.
  • C 2)我々は状態モードをcontextに多くの条件判断を置かない代替案と考えた.動作をステータスオブジェクトにパッケージすることで、context内で簡単にステータスオブジェクトを変更することでcontextの動作を変更することができます.