- 问题引入
有个一野蛮女友,她命令他男朋友帮她洗衣服。
我们用程序可以这么实现。
public class Boy {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boy(String name){
this.name = name;
}
}
public class Girl {
public void command(Boy boy){
System.out.print(boy.getName() + " 洗衣服");
}
public static void main(String[] args) {
Girl g = new Girl();
Boy b = new Boy("高尚");
g.command(b);
}
}
但是问题往往不是这么简单,这个野蛮女友越来越过分,她的需求在变化。
她要给她男朋友下各种各样的命令。如果按照刚才的实现。
我们就要不停的更改Girl的command的方法。
这不符合开闭原则。
其实,非常简单。我们只要把这个女孩的请求封装起来就行(所谓的封装变化)。
- 采用Command模式
public interface Command {
void execute();
}
public class ClothesCommand implements Command{
private Boy b;
public ClothesCommand(Boy b){
this.b = b;
}
@Override
public void execute() {
System.out.println(b.getName()+" 洗衣服");
}
}
class FoodCommand implements Command{
private Boy b;
public FoodCommand(Boy b){
this.b = b;
}
@Override
public void execute() {
System.out.println(b.getName()+" 买好吃的");
}
}
public class Boy {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Boy(String name){
this.name = name;
}
}
public class Girl {
private Command c;
public Command getC() {
return c;
}
public void setC(Command c) {
this.c = c;
}
public void command(){
c.execute();
}
public static void main(String[] args) {
Girl g = new Girl();
Boy b = new Boy("高尚");
g.setC(new ClothesCommand(b));
g.command();
g.setC(new FoodCommand(b));
g.command();
}
}
这样当女孩需求变化的时候,我们只需要创建一个新的实现类即可,而不用改动女孩的源码。
开闭原则的体现。
- Command模式与undo
最早GOF提出Command模式的时候,Command的模式还有一个比较主要的功能。
就是实现undo(撤销)。因为,命令的执行者往往知道,命令该如何撤销。
那么Command接口就可以这么设计。
public interface Command {
void execute();
void undo();
}
可以想象一下,这样一来。实现系统的撤销工作就非常容易了。
可以用一个栈,把系统做的动作都压入栈中,当需要撤销的时候。
弹出栈中的元素,执行undo()就ok了。
- 一些心得
设计这个东西,仁者见仁智者见智。
学习设计模式的时候,会有很多概念,很多人有不同的理解。
由于初学,很难融合这些人的观点。索性就不要去融合。找到一个适合自己的理解。
也不要死死的去扣合概念,概念是起到辅助和表述作用的。
如果不能很好的去扣合,还不如不去扣合。