命令模式主要通过中介Command实现了发出命令者和命令的执行者,也即Invoke类和Receiver的松耦合。
先看类图:
将请求封装成一个对象,从而使用户使用不同的请求把客户端参数化,请求队列或者记录日志,以及支持可撤销的操作。
看一个Android的例子
先定义两种画笔,这里是额外的,也就是说更这个设计模式没有太多关系,只是程序需要:
package com.example.yale.mydrawbrush.Brush;
import android.graphics.Path;
/**
* Created by Yale on 16/7/8.
*/
//抽象笔触
public interface IBrush {
/**
* 触点接触时
* @param path
* @param x
* @param y
*/
void down(Path path, float x, float y);
/**
* 触点移动式
* @param path
* @param x
* @param y
*/
void move(Path path, float x, float y);
/**
* 触点离开时
* @param path
* @param x
* @param y
*/
void up(Path path, float x, float y);
}
普通触笔
package com.example.yale.mydrawbrush.Brush;
import android.graphics.Path;
/**
* Created by Yale on 16/7/8.
*/
public class NormalBrush implements IBrush {
@Override
public void down(Path path, float x, float y) {
path.moveTo(x, y);
}
@Override
public void move(Path path, float x, float y) {
path.lineTo(x, y);
}
@Override
public void up(Path path, float x, float y) {
}
}
圆形触笔
package com.example.yale.mydrawbrush.Brush;
import android.graphics.Path;
/**
* Created by Yale on 16/7/8.
*/
public class CircleBrush implements IBrush {
@Override
public void down(Path path, float x, float y) {
}
@Override
public void move(Path path, float x, float y) {
path.addCircle(x, y, 10, Path.Direction.CW);
}
@Override
public void up(Path path, float x, float y) {
}
}
下面关键来了,我们先定义抽象命令接口,也就是绘制命令接口:
package com.example.yale.mydrawbrush.Brush;
/**
* Created by Yale on 16/7/8.
*/
import android.graphics.Canvas;
/**
* 对于每一次路径绘制,有两个命令:绘制命令和撤销命令
*/
public interface IDraw {
/**
* 绘制命令
* @param canvas 画布对象
*/
void draw(Canvas canvas);
/**
* 撤销命令
*/
void undo();
}
具体的绘制命令,也就是实现上面的接口
package com.example.yale.mydrawbrush.Brush;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
/**
* Created by Yale on 16/7/8.
*/
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() {
}
}
然后是命令的发出者Invoker,定义为DrawInvoker
package com.example.yale.mydrawbrush.Brush;
import android.graphics.Canvas;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Created by Yale on 16/7/8.
*/
public class DrawInvoker {
//绘制列表
private List<DrawPath> drawList = Collections.synchronizedList(new ArrayList<DrawPath>());
//重做列表
private List<DrawPath> redoList = Collections.synchronizedList(new ArrayList<DrawPath>());
public void add(DrawPath command) {
redoList.clear();
drawList.add(command);
}
public void undo() {
if (drawList.size() > 0) {
DrawPath undo = drawList.get(drawList.size() - 1);
drawList.remove(drawList.size() - 1);
undo.undo();
redoList.add(undo);
}
}
public void redo() {
if (redoList.size() > 0) {
DrawPath redoCommand = redoList.get(redoList.size() - 1);
redoList.remove(redoList.size() - 1);
drawList.add(redoCommand);
}
}
public void execute(Canvas canvas) {
if (drawList != null) {
for (DrawPath temp : drawList) {
temp.draw(canvas);
}
}
}
public boolean canRedo() {
return redoList.size() > 0;
}
public boolean canUndo() {
return drawList.size() > 0;
}
}
再定义命令的执行者,也就是Receiver,这里定义为DrawCanvas
package com.example.yale.mydrawbrush.Brush;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/**
* Created by Yale on 16/7/8.
*/
public class DrawCanvas extends SurfaceView implements SurfaceHolder.Callback{
public boolean isDrawing, isRunning;
private Bitmap mBitmap;
private DrawInvoker mInvoker;
private DrawThread mThread;
public DrawCanvas(Context context, AttributeSet attrs) {
super(context, attrs);
mInvoker = new DrawInvoker();
mThread = new DrawThread();
getHolder().addCallback(this);
}
public void add(DrawPath path){
mInvoker.add(path);
}
public void redo(){
isDrawing = true;
mInvoker.redo();
}
public void undo(){
isDrawing = true;
mInvoker.undo();
}
public boolean canUndo(){
return mInvoker.canUndo();
}
public boolean canRedo(){
return mInvoker.canRedo();
}
//
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
isRunning = true;
mThread.start();
}
//
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
}
//
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
boolean retry = true;
isRunning = false;
while(retry){
try{
mThread.join();
retry = false;
}catch (Exception e){
e.printStackTrace();
}
}
}
private class DrawThread extends Thread{
@Override
public void run() {
Canvas canvas = null;
while(isRunning) {
if (isDrawing) {
try {
canvas = getHolder().lockCanvas(null);
if (mBitmap == null) {
mBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
}
Canvas c = new Canvas(mBitmap);
c.drawColor(0, PorterDuff.Mode.CLEAR);
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
mInvoker.execute(c);
canvas.drawBitmap(mBitmap, 0, 0, null);
} finally {
getHolder().unlockCanvasAndPost(canvas);
}
isDrawing = false;
}
}
}
}
}
最后是把上述整合
package com.example.yale.mydrawbrush;
import android.graphics.Paint;
import android.graphics.Path;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import com.example.yale.mydrawbrush.Brush.CircleBrush;
import com.example.yale.mydrawbrush.Brush.DrawCanvas;
import com.example.yale.mydrawbrush.Brush.DrawPath;
import com.example.yale.mydrawbrush.Brush.IBrush;
import com.example.yale.mydrawbrush.Brush.NormalBrush;
import butterknife.Bind;
import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity {
// private DrawCanvas mCanvas;
private DrawPath mPath;
private Paint mPaint;
private IBrush mBrush;
@Bind(R.id.ac_draw_canvas)
DrawCanvas mCanvas;
@Bind(R.id.ac_draw_draw_operate_undo_btn)
Button btnUndo;
@Bind(R.id.ac_draw_draw_operate_redo_btn)
Button btnRedo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
mPaint = new Paint();
mPaint.setColor(0XFFFFFFFF);
mPaint.setStrokeWidth(3);
mCanvas.setOnTouchListener(new DrawTouchListener());
mBrush = new NormalBrush();
btnRedo.setEnabled(false);
btnUndo.setEnabled(false);
}
public void onClick(View view){
switch (view.getId()){
case R.id.ac_draw_color_red_btn:
mPaint = new Paint();
mPaint.setStrokeWidth(3);
mPaint.setColor(0XFFFF0000);
System.out.print("sfsfasfafd!$@#$!@#$!");
break;
case R.id.ac_draw_color_blue_btn:
mPaint = new Paint();
mPaint.setStrokeWidth(3);
mPaint.setColor(0XFF00FF00);
break;
case R.id.ac_draw_color_green_btn:
mPaint = new Paint();
mPaint.setStrokeWidth(3);
mPaint.setColor(0XFF0000FF);
break;
case R.id.ac_draw_draw_operate_undo_btn:
mCanvas.undo();
if(!mCanvas.canUndo()){
btnUndo.setEnabled(false);
}
btnRedo.setEnabled(true);
break;
case R.id.ac_draw_draw_operate_redo_btn:
mCanvas.redo();
if(!mCanvas.canRedo()){
btnUndo.setEnabled(false);
}
btnRedo.setEnabled(true);
break;
case R.id.ac_draw_operate_brush_circle_btn:
mBrush = new CircleBrush();
break;
case R.id.ac_draw_operate_brush_normal_btn:
mBrush = new NormalBrush();
break;
default:
break;
}
}
private class DrawTouchListener implements View.OnTouchListener{
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
mPath = new DrawPath();
mPath.paint = mPaint;
mPath.path = new Path();
mBrush.down(mPath.path, motionEvent.getX(), motionEvent.getY());
}else if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){
mBrush.move(mPath.path, motionEvent.getX(), motionEvent.getY());
}else if(motionEvent.getAction() == MotionEvent.ACTION_UP){
mBrush.up(mPath.path, motionEvent.getX(), motionEvent.getY());
mCanvas.add(mPath);
mCanvas.isDrawing = true;
btnUndo.setEnabled(true);
btnRedo.setEnabled(false);
}
return true;
}
}
}