diff --git a/notes/设计模式.md b/notes/设计模式.md index 61bd7f29..f3c62660 100644 --- a/notes/设计模式.md +++ b/notes/设计模式.md @@ -486,7 +486,7 @@ public class Client { ### 实现 -设计一个要控制,可以控制电灯开关。 +设计一个遥控器,可以控制电灯开关。

@@ -857,6 +857,306 @@ StatisticsDisplay.update: 1.0 1.0 1.0 ## 8. 状态(State) +### 意图 + +允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。 + +### 类图 + +

+ +### 实现 + +糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。 + +

+ +```java +public interface State { + /** + * 投入 25 分钱 + */ + void insertQuarter(); + + /** + * 退回 25 分钱 + */ + void ejectQuarter(); + + /** + * 转动曲柄 + */ + void turnCrank(); + + /** + * 发放糖果 + */ + void dispense(); +} +``` + +```java +public class HasQuarterState implements State { + + private GumballMachine gumballMachine; + + public HasQuarterState(GumballMachine gumballMachine) { + this.gumballMachine = gumballMachine; + } + + @Override + public void insertQuarter() { + System.out.println("You can't insert another quarter"); + } + + @Override + public void ejectQuarter() { + System.out.println("Quarter returned"); + gumballMachine.setState(gumballMachine.getNoQuarterState()); + } + + @Override + public void turnCrank() { + System.out.println("You turned..."); + gumballMachine.setState(gumballMachine.getSoldState()); + } + + @Override + public void dispense() { + System.out.println("No gumball dispensed"); + } +} +``` + +```java +public class NoQuarterState implements State { + + GumballMachine gumballMachine; + + public NoQuarterState(GumballMachine gumballMachine) { + this.gumballMachine = gumballMachine; + } + + @Override + public void insertQuarter() { + System.out.println("You insert a quarter"); + gumballMachine.setState(gumballMachine.getHasQuarterState()); + } + + @Override + public void ejectQuarter() { + System.out.println("You haven't insert a quarter"); + } + + @Override + public void turnCrank() { + System.out.println("You turned, but there's no quarter"); + } + + @Override + public void dispense() { + System.out.println("You need to pay first"); + } +} +``` + +```java +public class SoldOutState implements State { + + GumballMachine gumballMachine; + + public SoldOutState(GumballMachine gumballMachine) { + this.gumballMachine = gumballMachine; + } + + @Override + public void insertQuarter() { + System.out.println("You can't insert a quarter, the machine is sold out"); + } + + @Override + public void ejectQuarter() { + System.out.println("You can't eject, you haven't inserted a quarter yet"); + } + + @Override + public void turnCrank() { + System.out.println("You turned, but there are no gumballs"); + } + + @Override + public void dispense() { + System.out.println("No gumball dispensed"); + } +} +``` + +```java +public class SoldState implements State { + + GumballMachine gumballMachine; + + public SoldState(GumballMachine gumballMachine) { + this.gumballMachine = gumballMachine; + } + + @Override + public void insertQuarter() { + System.out.println("Please wait, we're already giving you a gumball"); + } + + @Override + public void ejectQuarter() { + System.out.println("Sorry, you already turned the crank"); + } + + @Override + public void turnCrank() { + System.out.println("Turning twice doesn't get you another gumball!"); + } + + @Override + public void dispense() { + gumballMachine.releaseBall(); + if (gumballMachine.getCount() > 0) { + gumballMachine.setState(gumballMachine.getNoQuarterState()); + } else { + System.out.println("Oops, out of gumballs"); + gumballMachine.setState(gumballMachine.getSoldOutState()); + } + } +} +``` + +```java +public class GumballMachine { + + private State soldOutState; + private State noQuarterState; + private State hasQuarterState; + private State soldState; + + private State state; + private int count = 0; + + public GumballMachine(int numberGumballs) { + count = numberGumballs; + soldOutState = new SoldOutState(this); + noQuarterState = new NoQuarterState(this); + hasQuarterState = new HasQuarterState(this); + soldState = new SoldState(this); + + if (numberGumballs > 0) { + state = noQuarterState; + } else { + state = soldOutState; + } + } + + public void insertQuarter() { + state.insertQuarter(); + } + + public void ejectQuarter() { + state.ejectQuarter(); + } + + public void turnCrank() { + state.turnCrank(); + state.dispense(); + } + + public void setState(State state) { + this.state = state; + } + + public void releaseBall() { + System.out.println("A gumball comes rolling out the slot..."); + if (count != 0) { + count -= 1; + } + } + + public State getSoldOutState() { + return soldOutState; + } + + public State getNoQuarterState() { + return noQuarterState; + } + + public State getHasQuarterState() { + return hasQuarterState; + } + + public State getSoldState() { + return soldState; + } + + public int getCount() { + return count; + } +} +``` + +```java +public class Client { + + public static void main(String[] args) { + GumballMachine gumballMachine = new GumballMachine(5); + + gumballMachine.insertQuarter(); + gumballMachine.turnCrank(); + + gumballMachine.insertQuarter(); + gumballMachine.ejectQuarter(); + gumballMachine.turnCrank(); + + gumballMachine.insertQuarter(); + gumballMachine.turnCrank(); + gumballMachine.insertQuarter(); + gumballMachine.turnCrank(); + gumballMachine.ejectQuarter(); + + gumballMachine.insertQuarter(); + gumballMachine.insertQuarter(); + gumballMachine.turnCrank(); + gumballMachine.insertQuarter(); + gumballMachine.turnCrank(); + gumballMachine.insertQuarter(); + gumballMachine.turnCrank(); + } +} +``` + +```html +You insert a quarter +You turned... +A gumball comes rolling out the slot... +You insert a quarter +Quarter returned +You turned, but there's no quarter +You need to pay first +You insert a quarter +You turned... +A gumball comes rolling out the slot... +You insert a quarter +You turned... +A gumball comes rolling out the slot... +You haven't insert a quarter +You insert a quarter +You can't insert another quarter +You turned... +A gumball comes rolling out the slot... +You insert a quarter +You turned... +A gumball comes rolling out the slot... +Oops, out of gumballs +You can't insert a quarter, the machine is sold out +You turned, but there are no gumballs +No gumball dispensed +``` + ## 9. 策略(Strategy) ### 意图 @@ -870,7 +1170,17 @@ StatisticsDisplay.update: 1.0 1.0 1.0 - Strategy 接口定义了一个算法族,它们都具有 BehaviorInterface() 方法。 - Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 BehaviorInterface(),setStrategy(in Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。 -

+

+ +### 与状态模式的比较 + +状态模式的类图和策略模式一样,并且都是能够动态改变对象的行为。 + +但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。 + +所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。 + +状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。 ### 实现 diff --git a/pics/396be981-3f2c-4fd9-8101-dbf9c841504b.jpg b/pics/396be981-3f2c-4fd9-8101-dbf9c841504b.jpg new file mode 100644 index 00000000..60c19f88 Binary files /dev/null and b/pics/396be981-3f2c-4fd9-8101-dbf9c841504b.jpg differ diff --git a/pics/abb3e0d1-c1bd-45d0-8190-73c74a9f6679.png b/pics/abb3e0d1-c1bd-45d0-8190-73c74a9f6679.png new file mode 100644 index 00000000..6a6bf78f Binary files /dev/null and b/pics/abb3e0d1-c1bd-45d0-8190-73c74a9f6679.png differ diff --git a/pics/b8dd708d-f372-4b04-b828-1dd99021c244.png b/pics/b8dd708d-f372-4b04-b828-1dd99021c244.png new file mode 100644 index 00000000..c74e816e Binary files /dev/null and b/pics/b8dd708d-f372-4b04-b828-1dd99021c244.png differ