-
Notifications
You must be signed in to change notification settings - Fork 109
/
Command.kt
144 lines (109 loc) · 3.32 KB
/
Command.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package design_patterns
/**
*
* Command is a behavioral pattern that encapsulates a request to perform an action as a separate object
*
*/
// StereoSystem is the receiver that performs the action
class StereoSystem {
private var hasTurnedOn = false
private var volume = 50
val currentState: String
get() = """
running status: $hasTurnedOn
volume value: $volume
""".trimIndent()
fun turnOn() {
hasTurnedOn = true
}
fun turnOff() {
hasTurnedOn = false
}
fun increaseVolume() {
if (!hasTurnedOn) return
if (volume < 100) {
volume += 10
}
}
fun decreaseVolume() {
if (!hasTurnedOn) return
if (volume > 0) {
volume -= 10
}
}
}
interface StereoSystemCommand {
fun execute()
fun undo() : Boolean
}
// this command encapsulates a request to increase the volume in StereoSystem
class IncreaseVolumeCommand(private val stereoSystem: StereoSystem) : StereoSystemCommand {
override fun execute() {
stereoSystem.increaseVolume()
}
override fun undo(): Boolean {
stereoSystem.decreaseVolume()
return true
}
}
// this command encapsulates a request to decrease the volume in StereoSystem
class DecreaseVolumeCommand(private val stereoSystem: StereoSystem) : StereoSystemCommand {
override fun execute() {
stereoSystem.decreaseVolume()
}
override fun undo(): Boolean {
stereoSystem.increaseVolume()
return true
}
}
// this command encapsulates a request to turn on StereoSystem
class TurnOnCommand(private val stereoSystem: StereoSystem) : StereoSystemCommand {
override fun execute() {
stereoSystem.turnOn()
}
override fun undo(): Boolean {
stereoSystem.turnOff()
return true
}
}
// this command encapsulates a request to turn off StereoSystem
class TurnOffCommand(private val stereoSystem: StereoSystem) : StereoSystemCommand {
override fun execute() {
stereoSystem.turnOff()
}
override fun undo() = false
}
// we can also create the command that combines others
class MacroCommand(private vararg val commands: StereoSystemCommand) : StereoSystemCommand {
override fun execute() {
for (command in commands) {
command.execute()
}
}
override fun undo(): Boolean {
for (command in commands.reversed()) {
val isNotCancelableCommand = !command.undo()
if (isNotCancelableCommand) return false
}
return true
}
}
// StereoSystemRemoteControl executes commands without breaking their encapsulation
class StereoSystemRemoteControl(private val buttons: Map<String, StereoSystemCommand> = mapOf()) {
// we only know about StereoSystemCommand interface
private val commandHistory = mutableListOf<StereoSystemCommand>()
fun pressButton(name: String) {
val command = buttons[name]
if (command != null) {
command.execute()
commandHistory.add(command)
}
}
fun pressUndoButton() {
val lastCommand = commandHistory.removeLastOrNull()
if (lastCommand != null) {
val isNotCancelableCommand = !lastCommand.undo()
if (isNotCancelableCommand) commandHistory.clear()
}
}
}