-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
271 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# State | ||
内部状態が変化したときにオブジェクトの動作を変更できるようにする動作設計パターン | ||
|
||
現在の状態に応じて動作が異なるオブジェクトがあり、状態の数が膨大で、状態固有のコードが頻繁に変更される場合 | ||
|
||
### メリット | ||
- 単一責任の原則。特定の状態に関連するコードを個別のクラスに編成します。 | ||
- オープン/クローズド原則。既存の状態クラスやコンテキストを変更せずに、新しい状態を導入します。 | ||
- かさばるステートマシンの条件を排除することにより、コンテキストのコードを簡素化します。 | ||
|
||
### デメリット | ||
- ステートマシンの状態が少ないか、ほとんど変更されない場合、やりすぎになる可能性 | ||
|
||
### 他パターンとの関係性 | ||
- Bridge、State、Strategy(およびある程度Adapter)の構造は非常に似ているが、他のオブジェクトに作業を委任する構成に基づいてる | ||
- StateはStrategyの延長 | ||
|
||
### 例題 | ||
- 自動販売機 | ||
- 4つの状態があるとする | ||
- hasItem | ||
- noItem | ||
- itemRequested | ||
- hasMoney | ||
|
||
- また4つのアクションがある | ||
- アイテムを選択 | ||
- アイテムを追加 | ||
- お金を挿入する | ||
- ディスペンスアイテム | ||
|
||
- Stateはオブジェクトがさまざまな状態になる可能性があり、に次の状態に切り替わる |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package state | ||
|
||
import "fmt" | ||
|
||
type hasItemState struct { | ||
vendingMachine *vendingMachine | ||
} | ||
|
||
func (i *hasItemState) requestItem() error { | ||
if i.vendingMachine.itemCount == 0 { | ||
i.vendingMachine.setState(i.vendingMachine.noItem) | ||
return fmt.Errorf("No item present") | ||
} | ||
fmt.Printf("Item requestd\n") | ||
i.vendingMachine.setState(i.vendingMachine.itemRequested) | ||
return nil | ||
} | ||
|
||
func (i *hasItemState) addItem(count int) error { | ||
fmt.Printf("%d items added\n", count) | ||
i.vendingMachine.incrementItemCount(count) | ||
return nil | ||
} | ||
|
||
func (i *hasItemState) insertMoney(money int) error { | ||
return fmt.Errorf("Please select item first") | ||
} | ||
func (i *hasItemState) dispenseItem() error { | ||
return fmt.Errorf("Please select item first") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package state | ||
|
||
import "fmt" | ||
|
||
type hasMoneyState struct { | ||
vendingMachine *vendingMachine | ||
} | ||
|
||
func (i *hasMoneyState) requestItem() error { | ||
return fmt.Errorf("Item dispense in progress") | ||
} | ||
|
||
func (i *hasMoneyState) addItem(count int) error { | ||
return fmt.Errorf("Item dispense in progress") | ||
} | ||
|
||
func (i *hasMoneyState) insertMoney(money int) error { | ||
return fmt.Errorf("Item out of stock") | ||
} | ||
func (i *hasMoneyState) dispenseItem() error { | ||
fmt.Println("Dispensing Item") | ||
i.vendingMachine.itemCount = i.vendingMachine.itemCount - 1 | ||
if i.vendingMachine.itemCount == 0 { | ||
i.vendingMachine.setState(i.vendingMachine.noItem) | ||
} else { | ||
i.vendingMachine.setState(i.vendingMachine.hasItem) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package state | ||
|
||
import "fmt" | ||
|
||
type itemRequestedState struct { | ||
vendingMachine *vendingMachine | ||
} | ||
|
||
func (i *itemRequestedState) requestItem() error { | ||
return fmt.Errorf("Item already requested") | ||
} | ||
|
||
func (i *itemRequestedState) addItem(count int) error { | ||
return fmt.Errorf("Item Dispense in progress") | ||
} | ||
|
||
func (i *itemRequestedState) insertMoney(money int) error { | ||
if money < i.vendingMachine.itemPrice { | ||
fmt.Errorf("Inserted money is less. Please insert %d", i.vendingMachine.itemPrice) | ||
} | ||
fmt.Println("Money entered is ok") | ||
i.vendingMachine.setState(i.vendingMachine.hasMoney) | ||
return nil | ||
} | ||
func (i *itemRequestedState) dispenseItem() error { | ||
return fmt.Errorf("Please insert money first") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package state | ||
|
||
import "fmt" | ||
|
||
type noItemState struct { | ||
vendingMachine *vendingMachine | ||
} | ||
|
||
func (i *noItemState) requestItem() error { | ||
return fmt.Errorf("Item out of stock") | ||
} | ||
|
||
func (i *noItemState) addItem(count int) error { | ||
i.vendingMachine.incrementItemCount(count) | ||
i.vendingMachine.setState(i.vendingMachine.hasItem) | ||
return nil | ||
} | ||
|
||
func (i *noItemState) insertMoney(money int) error { | ||
return fmt.Errorf("Item out of stock") | ||
} | ||
func (i *noItemState) dispenseItem() error { | ||
return fmt.Errorf("Item out of stock") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package state | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
) | ||
|
||
type state interface { | ||
addItem(int) error | ||
requestItem() error | ||
insertMoney(money int) error | ||
dispenseItem() error | ||
} | ||
|
||
func main() { | ||
vendingMachine := newVendingMachine(1, 10) | ||
|
||
err := vendingMachine.requestItem() | ||
if err != nil { | ||
log.Fatalf(err.Error()) | ||
} | ||
|
||
err = vendingMachine.insertMoney(10) | ||
if err != nil { | ||
log.Fatalf(err.Error()) | ||
} | ||
|
||
err = vendingMachine.dispenseItem() | ||
if err != nil { | ||
log.Fatalf(err.Error()) | ||
} | ||
|
||
fmt.Println() | ||
|
||
err = vendingMachine.addItem(2) | ||
if err != nil { | ||
log.Fatalf(err.Error()) | ||
} | ||
|
||
fmt.Println() | ||
|
||
err = vendingMachine.requestItem() | ||
if err != nil { | ||
log.Fatalf(err.Error()) | ||
} | ||
|
||
err = vendingMachine.insertMoney(10) | ||
if err != nil { | ||
log.Fatalf(err.Error()) | ||
} | ||
|
||
err = vendingMachine.dispenseItem() | ||
if err != nil { | ||
log.Fatalf(err.Error()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package state | ||
|
||
import "testing" | ||
|
||
func TestState(t *testing.T) { | ||
main() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package state | ||
|
||
import "fmt" | ||
|
||
type vendingMachine struct { | ||
hasItem state | ||
itemRequested state | ||
hasMoney state | ||
noItem state | ||
|
||
currentState state | ||
|
||
itemCount int | ||
itemPrice int | ||
} | ||
|
||
func newVendingMachine(itemCount, itemPrice int) *vendingMachine { | ||
v := &vendingMachine{ | ||
itemCount: itemCount, | ||
itemPrice: itemPrice, | ||
} | ||
hasItemState := &hasItemState{ | ||
vendingMachine: v, | ||
} | ||
itemRequestedState := &itemRequestedState{ | ||
vendingMachine: v, | ||
} | ||
hasMoneyState := &hasMoneyState{ | ||
vendingMachine: v, | ||
} | ||
noItemState := &noItemState{ | ||
vendingMachine: v, | ||
} | ||
|
||
v.setState(hasItemState) | ||
v.hasItem = hasItemState | ||
v.itemRequested = itemRequestedState | ||
v.hasMoney = hasMoneyState | ||
v.noItem = noItemState | ||
return v | ||
} | ||
|
||
func (v *vendingMachine) requestItem() error { | ||
return v.currentState.requestItem() | ||
} | ||
|
||
func (v *vendingMachine) addItem(count int) error { | ||
return v.currentState.addItem(count) | ||
} | ||
|
||
func (v *vendingMachine) insertMoney(money int) error { | ||
return v.currentState.insertMoney(money) | ||
} | ||
|
||
func (v *vendingMachine) dispenseItem() error { | ||
return v.currentState.dispenseItem() | ||
} | ||
|
||
func (v *vendingMachine) setState(s state) { | ||
v.currentState = s | ||
} | ||
|
||
func (v *vendingMachine) incrementItemCount(count int) { | ||
fmt.Printf("Adding %d items\n", count) | ||
v.itemCount = v.itemCount + count | ||
} |