1.场景问题解决
1.1 场景描述
智能家居项目.
家里有电灯,音箱,电视等子设备,有各自的开关接口.
现需要一个:总的开关设备,将所有的家居都能控制起来.
1.2 OO设计
if,else判断,或者Case when处理.
1.3 需求变动
如果增加新或修改设备,就要修改总开关设备.
1.4 带来问题
要求总开关设备:扩展性好、维护性好.当前oo设计耦合性强.
2.用设计模式改进
2.1 分析
2.2 重新设计
3.设计模式总结
3.1 定义
命令模式: 将请求、命令、动作等封装成对象,这样可以让项目使用这些对象来参数化其他对象。使得命令的请求者和执行者解耦
3.2 分析思路
- interface Command
public interface Command {
public void execute();
public void undo();
}
- 实现类(LightOnCommand[灯开],LightOffCommand[灯关],StereoOnCommand[音响开],StereoOffCommand[印象关],StereoAddVolCommand[音箱声音加],StereoSubVolCommand[音箱声音减],NoCommand[空命令],MarcoCommand[宏命令])
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light){
this.light=light;
}
@Override
public void execute() {
light.On();
}
@Override
public void undo() {
light.Off();
}
}
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light){
this.light=light;
}
@Override
public void execute() {
light.Off();
}
@Override
public void undo() {
light.On();
}
}
public class StereoOnCommand implements Command {
private Stereo setreo;
public StereoOnCommand(Stereo setreo) {
this.setreo=setreo;
}
@Override
public void execute() {
setreo.On();
setreo.SetCd();
}
@Override
public void undo() {
setreo.Off();
}
}
public class StereoOffCommand implements Command {
private Stereo setreo;
public StereoOffCommand(Stereo setreo){
this.setreo=setreo;
}
@Override
public void execute() {
setreo.Off();
}
@Override
public void undo() {
setreo.On();
setreo.SetCd();
}
}
public class StereoAddVolCommand implements Command {
private Stereo setreo;
public StereoAddVolCommand(Stereo setreo) {
this.setreo=setreo;
}
@Override
public void execute() {
int vol= setreo.GetVol();
if(vol<11) {
setreo.SetVol(++vol);
}
}
@Override
public void undo() {
int vol= setreo.GetVol();
if(vol>0){
setreo.SetVol(--vol);
}
}
}
public class StereoSubVolCommand implements Command {
private Stereo setreo;
public StereoSubVolCommand(Stereo setreo){
this.setreo=setreo;
}
@Override
public void execute() {
int vol= setreo.GetVol();
if(vol>0){
setreo.SetVol(--vol);
}
}
@Override
public void undo() {
int vol= setreo.GetVol();
if(vol<11){
setreo.SetVol(++vol);
}
}
}
public class NoCommand implements Command {
@Override
public void execute() {
}
@Override
public void undo() {
}
}
public class MarcoCommand implements Command {
private Command[] commands;
public MarcoCommand(Command[] commands) {
this.commands = commands;
}
@Override
public void execute() {
for (int i = 0, len = commands.length; i < len; i++) {
commands[i].execute();
}
}
@Override
public void undo() {
for (int i = commands.length - 1; i >= 0; i--) {
commands[i].undo();
}
}
}
--- CommandModeControl(插槽[命令集合器])
public class CommandModeControl implements Control{
private Command[] onCommands;
private Command[] offCommands;
private Stack<Command> stack=new Stack<Command>();
public CommandModeControl(){
onCommands=new Command[5];
offCommands=new Command[5];
Command noCommand=new NoCommand();
for(int i=0,len=onCommands.length;i<len;i++)
{
onCommands[i]=noCommand;
offCommands[i]=noCommand;
}
}
public void setCommand(int slot,Command onCommand,Command offCommand){
onCommands[slot]=onCommand;
offCommands[slot]=offCommand;
}
@Override
public void onButton(int slot) {
onCommands[slot].execute();
stack.push(onCommands[slot]);
}
@Override
public void offButton(int slot) {
offCommands[slot].execute();
stack.push(offCommands[slot]);
}
@Override
public void undoButton() {
stack.pop().undo();
}
}
-- 测试类
public class CommandControlTest {
public static void main(String[] args) {
CommandModeControl control = new CommandModeControl();
MarcoCommand onmarco,offmarco;
Light bedroomlight = new Light("BedRoom");
Light kitchlight = new Light("Kitch");
Stereo stereo = new Stereo();
LightOnCommand bedroomlighton = new LightOnCommand(bedroomlight);
LightOffCommand bedroomlightoff = new LightOffCommand(bedroomlight);
LightOnCommand kitchlighton = new LightOnCommand(kitchlight);
LightOffCommand kitchlightoff = new LightOffCommand(kitchlight);
Command[] oncommands={bedroomlighton,kitchlighton};
Command[] offcommands={bedroomlightoff,kitchlightoff};
onmarco=new MarcoCommand(oncommands);
offmarco=new MarcoCommand(offcommands);
StereoOnCommand stereoOn = new StereoOnCommand(stereo);
StereoOffCommand stereoOff = new StereoOffCommand(stereo);
StereoAddVolCommand stereoaddvol = new StereoAddVolCommand(stereo);
StereoSubVolCommand stereosubvol = new StereoSubVolCommand(stereo);
control.setCommand(0, bedroomlighton, bedroomlightoff);
control.setCommand(1, kitchlighton, kitchlightoff);
control.setCommand(2, stereoOn, stereoOff);
control.setCommand(3, stereoaddvol, stereosubvol);
control.setCommand(4, onmarco, offmarco);
control.onButton(0);
control.undoButton();
//control.offButton(0);
control.onButton(1);
control.offButton(1);
control.onButton(2);
control.onButton(3);
control.offButton(3);
control.undoButton();
control.offButton(2);
control.undoButton();
control.onButton(4);
control.offButton(4);
}
}
3.3 总结归纳
转换思想,将命令定义为对象.而不是动作.虽然类、代码更多了,但是解耦了,扩展新也更强了,可以整个每个对象(灯具,音箱)来执行响应的动作。
4. 设计模式使用场景及注意
5.参考文章
内容总计于HeadFirst设计模式及相关视频