命令模式
命令模式
一、简介
定义:将一个请求封装成一个对象,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
二、使用场景
在某些场合,比如需要对行为进行记录、撤销或重做、事务等处理时可以使用命令模式
三、简单实现
以实现一个简单的绘图板为例。
//抽象触笔类
public interface IBrush{
void down(Path path, float x, float y);
void up(Path path,float x,float y);
void move(Path path,float x,float y);
}
public class NormalBrush implements IBrush{
@Override
public void down(Path path, float x, float y) {
path.moveTo(x,y);
}
@Override
public void up(Path path, float x, float y) {
}
@Override
public void move(Path path, float x, float y) {
path.lineTo(x,y);
}
}
public class CircleBrush implements IBrush{
@Override
public void down(Path path, float x, float y) {
}
@Override
public void up(Path path, float x, float y) {
}
@Override
public void move(Path path, float x, float y) {
path.addCircle(x,y,10,Path.Direction.CW);
}
}
//命令接口
public interface IDraw{
void draw(Canvas canvas);
void undo();
}
public class DrawPath implements IDraw{
public Path path;
public Paint paint;
@Override
public void draw(Canvas canvas) {
canvas.drawPath(path,paint);
}
@Override
public void undo() {
}
}
//请求者
public class Invoker{
//绘制列表
private List<DrawPath> drawPathList= Collections.synchronizedList(new ArrayList<>());
//重做列表
private List<DrawPath> redoPathList= Collections.synchronizedList(new ArrayList<>());
public void add(DrawPath command){
redoPathList.clear();
drawPathList.add(command);
}
public void undo(){
if (drawPathList.size()>0){
DrawPath undo=drawPathList.get(drawPathList.size()-1);
drawPathList.remove(drawPathList.size()-1);
undo.undo();
redoPathList.add(undo);
}
}
public void redo(){
if (redoPathList.size()>0){
DrawPath redo=redoPathList.get(redoPathList.size()-1);
redoPathList.remove(redoPathList.size()-1);
drawPathList.add(redo);
}
}
public void execute(Canvas canvas){
if (drawPathList!=null){
for (DrawPath drawPath : drawPathList) {
drawPath.draw(canvas);
}
}
}
public boolean canRedo(){
return redoPathList.size()>0;
}
public boolean canUndo(){
return drawPathList.size()>0;
}
}
public void main(){
Invoker invoker=new Invoker();
invoker.add(new DrawPath());
invoker.redo();
}
四、小结
命令模式并不局限于GUI在很多地方都可以使用,比如在onClick方法中使用分支语句来处理不同按钮的点击事件,这时候如果每个分支的逻辑很复杂就可以使用命令模式,一个分支对应一条命令以增强代码可读性。
命令模式的缺点是会产生大量的类。