Command pattern case from book "Head First Design Pattern"
https://github.com/Johnjunzhang/CommandPattern
####Step 1 #####Motivation: Bad Smell: Divergent Change
#####Intent Encapsulate a request as a object
#####Mechanics
- Extract Method: Extract light.On() to LightOn method in RemoteControl.cs
- Create file from template: Generate class LightOnCommand
- Move Method:
- Generate Code: Generate constructor with Light parameter in LightOnCommand.cs
- Introduce and initialize filed 'light'
- Make field 'light' public
- Introduce variable: add new LightOnCommand(light) in LightOn method in RemoteControl.cs
- Use lightOnCommand.light.On() to replace with light.On()
- Introduce parameter: lightOnCommand
- Make 'LightOn' static
- Make 'LightOn' Method Non-Static with Visibility 'public'
- Inline lightOnCommand and remove redundant qualifier:this.
- Make field "light" private
- Use 1-3 to extract CeilingHighCommand class
- Use 1-3 to extract StereoOnCommand class
- Use 1-3 to extract LightOffCommand class
- Use 1-3 to extract CeilingOffCommand class
- Use 1-3 to extract StereoOffCommand class
#####Result git checkout step1
####Step 2 #####Motivation Bad Smell: Alternative Classes with Different Interfaces
#####Intent Make requests with same interface
#####Mechanics
- Rename: LightOn, LightOff, CeilingHigh, CeilingOff, StereoOn, StereoOff to Execute
- Extract Interface: Extract ICommand from LightOnCommand with Execute method.
- Let other Commands to inherit ICommand interface.
#####Result git checkout step2
####Step 3 #####Motivation Bad Smell: Switch Statements
#####Intent
Map the receiver with the action
#####Mechanics
- Introduce variable: lightOnCommand, CeilingHighCommand, StereoOnCommand in RemoteControl.cs
- New Dictionary<int, ICommand>(), Introduce field: onCommands
- commands.Add(1, lightOnCommand)
- Use commands[slot].Execute() to replace lightOnCommand.Execute()
- Use 3-4 to replace ceilingHighCommand.Execute()
- Use 3-4 to replace stereoOnCommand.Execute()
- Remove If conditions
- Use 1-7 to refactoring Off method
#####Result git checkout step3
####Step 4 #####Motivation Bad Smell: Functions Should Do One Thing
#####Intent Decouple instantiate command from execution request
#####Mechanics
- Extract Method: Extract commands initialize to 'GetOnCommands' method in RemoteControl.cs
- Introduce Field: Introduce field 'getOnCommands' and initialize in Constructor(s)
- Inline Field: onCommands
- Use 1-3 to refactoring Off method
#####Result git checkout step4
####Step 5 #####Motivation Bad Smell: Primitive Obsession
#####Intent Use user defined method to replace dictionary add
#####Mechanics
- Introduce Filed: Introduce 'onCommands' and initialize in Field initializer
- Extract Method: Extract add lightOnCommand to SetOnCommand method
- Introduce Parameter: Introduce slot number 1 to parameter
- Use SetOnCommand for add ceiling and stereo
- Use 1-4 to refactoring Off method.
#####Result git checkout step5
####Step 6 #####Motivation Bad Smell: Temporary Field
#####Intent Remove temporary field
#####Mechanics
- Inline Method: GetOnCommands()
- Inline Field: getOnCommands
- Use 1-2 to remove getOffCommands
- Inline Field: light, ceiling, stereo
#####Result git checkout step6
####Step 7 #####Motivation Bad Smell: Divergent Change
#####Intent Parameterize clients with different request
#####Mechanics
- Replace Constructor With Factory Method
- Extract Method: Extract codes in constructor to SetCommands method
- Introduce Variable: remoteControl in factory method
- Use remoteControl.SetCommands method in factory method to replace SetCommands in constructor
- Safe Delete: parameters and its constructor
- Inline Method: SetCommands()
- Change SetOnCommand to public
- Change SetOffCommand to public
- Inline Method: Inline CreateRemoteControl factory method
- Remove useless SetOnCommand, SetOffCommand calls in RemoteControlFact
#####Result git checkout step7
###Further Exercises
- Read the "Refactoring" book about the bad smells and mechanics have been used. This is the website version of the book for quick reference: http://sourcemaking.com/refactoring
- Implement 'Null Object' for dealing with unset slot gracefully.
- Implement Undo function for understanding more about benefit from Command Pattern.
- Implement Macro function for understanding more about benefit from Command Pattern.