State model design pattern (a)

I thought that all things are easy in the countryside, but every time I turned around there are more requests to change after another. I am going to collapse! ---- When Xiao Bian read these words, very mixed feelings, the world of design patterns is really not so easy to understand, but fortunately I'm still learning.

Basic common sense: Strategy mode and state mode are twins, separated at birth only. Strategy pattern around interchangeable algorithms to create a successful business. However, the state is taking a more noble way, it objects to help control their behavior by changing the internal state of the object.

Let's look at all objects of the village, and this time came up with nothing. They found that as long as installed in the candy machine in the CPU, you can increase sales by network monitoring inventory, and can accurately determine customer satisfaction. All, there is the following of this idea:

The state machine 101

How do we get real code from state diagram? The following is a simple description of the state machine

  1. First, find all of the state:

We have: no 25 cents, 25 cents, sold candy, candy sold in four states

  1. Next, create an instance variable to hold the current state, then define the value for each state:
    final static int SOLD_OUT = 0;
    final static int NO_QUARTER = 1;
    final static int HAS_QUARTER = 2;
    final static int SOLD = 3;
 
    int state = SOLD_OUT;
  1. Now, the operation of all systems we can integrate occur:

Put 25 cents, 25 cents return, turn the crank, release candy

  1. Now, we create a class that acts like a state machine. For each action, we have created a corresponding method, these methods use a conditional statement to determine in each state what behavior is appropriate. For example, to "put 25 cents" this action, we can write the corresponding method looks like the following:
public void insertQuarter() {
    if (state == HAS_QUARTER) {
        System.out.println("You can't insert another quarter");
    } else if (state == NO_QUARTER) {
        state = HAS_QUARTER;
        System.out.println("You inserted a quarter");
    } else if (state == SOLD_OUT) {
        System.out.println("You can't insert a quarter, the machine is old out");
    } else if (state == SOLD) {
        System.out.println("Please wait, we're already giving you a gumball");
    }
}

Write Code

Now we realize the candy machine. We know you want to use an instance variable to hold the current state, and then convert to deal with all possible actions, behavior and status. We need to implement moving over include: put 25 cents, 25 cents return, turn the crank and the issuance of candy; also check whether the candy sold out.

public class GumballMachine {
 
    final static int SOLD_OUT = 0;
    final static int NO_QUARTER = 1;
    final static int HAS_QUARTER = 2;
    final static int SOLD = 3;
 
    int state = SOLD_OUT;
    int count = 0;
  
    public GumballMachine(int count) {
        this.count = count;
        if (count > 0) {
            state = NO_QUARTER;
        }
    }
    // 当有25分钱投进来,就会执行这里
    public void insertQuarter() {
        if (state == HAS_QUARTER) {
            System.out.println("You can't insert another quarter");
        } else if (state == NO_QUARTER) {
            state = HAS_QUARTER;
            System.out.println("You inserted a quarter");
        } else if (state == SOLD_OUT) {
            System.out.println("You can't insert a quarter, the machine is sold out");
        } else if (state == SOLD) {
            System.out.println("Please wait, we're already giving you a gumball");
        }
    }

    // 现在,如果顾客试着退回25分钱
    public void ejectQuarter() {
        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) {
            System.out.println("Sorry, you already turned the crank");
        } else if (state == SOLD_OUT) {
            System.out.println("You can't eject, you haven't inserted a quarter yet");
        }
    }
 
    // 顾客试着转动曲柄
    public void turnCrank() {
        if (state == SOLD) {
            System.out.println("Turning twice doesn't get you another gumball!");
        } else if (state == NO_QUARTER) {
            System.out.println("You turned but there's no quarter");
        } else if (state == SOLD_OUT) {
            System.out.println("You turned, but there are no gumballs");
        } else if (state == HAS_QUARTER) {
            System.out.println("You turned...");
            state = SOLD;
            dispense();
        }
    }
 
    // 调用此方法,发放糖果
    private void dispense() {
        if (state == SOLD) {
            System.out.println("A gumball comes rolling out the slot");
            count = count - 1;
            if (count == 0) {
                System.out.println("Oops, out of gumballs!");
                state = SOLD_OUT;
            } else {
                state = NO_QUARTER;
            }
        } else if (state == NO_QUARTER) {
            System.out.println("You need to pay first");
        } else if (state == SOLD_OUT) {
            System.out.println("No gumball dispensed");
        } else if (state == HAS_QUARTER) {
            System.out.println("No gumball dispensed");
        }
    }
 
    public void refill(int numGumBalls) {
        this.count = numGumBalls;
        state = NO_QUARTER;
    }

    public String toString() {
        StringBuffer result = new StringBuffer();
        result.append("\nMighty Gumball, Inc.");
        result.append("\nJava-enabled Standing Gumball Model #2004\n");
        result.append("Inventory: " + count + " gumball");
        if (count != 1) {
            result.append("s");
        }
        result.append("\nMachine is ");
        if (state == SOLD_OUT) {
            result.append("sold out");
        } else if (state == NO_QUARTER) {
            result.append("waiting for quarter");
        } else if (state == HAS_QUARTER) {
            result.append("waiting for turn of crank");
        } else if (state == SOLD) {
            result.append("delivering a gumball");
        }
        result.append("\n");
        return result.toString();
    }
}

Now, let's get into a little internal testing, look meets the requirements.

public class WinnerState implements State {
    GumballMachine gumballMachine;
 
    public WinnerState(GumballMachine gumballMachine) {
        this.gumballMachine = gumballMachine;
    }
 
    public void insertQuarter() {
        System.out.println("Please wait, we're already giving you a Gumball");
    }
 
    public void ejectQuarter() {
        System.out.println("Please wait, we're already giving you a Gumball");
    }
 
    public void turnCrank() {
        System.out.println("Turning again doesn't get you another gumball!");
    }
 
    public void dispense() {
        gumballMachine.releaseBall();
        if (gumballMachine.getCount() == 0) {
            gumballMachine.setState(gumballMachine.getSoldOutState());
        } else {
            gumballMachine.releaseBall();
            System.out.println("YOU'RE A WINNER! You got two gumballs for your quarter");
            if (gumballMachine.getCount() > 0) {
                gumballMachine.setState(gumballMachine.getNoQuarterState());
            } else {
                System.out.println("Oops, out of gumballs!");
                gumballMachine.setState(gumballMachine.getSoldOutState());
            }
        }
    }
 
    public void refill() { }
    
    public String toString() {
        return "despensing two gumballs for your quarter, because YOU'RE A WINNER!";
    }
}

Long run result here is not to print it, a friend in need be performed according to your own code.

Changing demand, and the need for new design

Now, when cranking customer requirements, there is a 10% chance of falling is two candy (multi send you a), how should you do it?

Our plan is this: do not maintain our existing code, we rewrite it so that the state of the object encapsulated in their class, and then entrusted to the current state if action occurs. So, we have to do is:

  1. First, we define a State interface. In this interface, the operation of each candy machine has a corresponding method
  2. Then for each state class implementing a state machine. These will be responsible for the machine in the corresponding state act
  3. Finally, we want to get rid of the old condition code, instead of the way would be entrusted to the state class action

You will see that we not only comply with the design principles, in fact, we also achieved a state mode. Next, we define the state of interfaces and classes, as follows:

Well, up to now, our next step is certainly going to realize how the transformation, right. Over here, for everyone to keep, go to thinking to think, how to transform. With ideas, with class diagrams, to see how you like it. Our next announced.

Love life, love of learning and perception, kicked love

Guess you like

Origin www.cnblogs.com/dimple91/p/11231810.html