Command模式,将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化(可以被传递、存储、重复利用);对请求排队或记录请求日志,以及支持可撤消的操作。
public class Unit : MonoBehaviour
{
public void Move(Vector3 translation)
{
transform.Translate(translation);
}
}
public abstract class Command
{
protected float time;
public float Time { get { return time; } }
public virtual void execute(Unit unit) { }
public virtual void undo(Unit unit) { }
}
public class MoveCommand : Command
{
private Vector3 translation;
public MoveCommand(Vector3 trans, float t)
{
translation = trans;
time = t;
}
public override void execute(Unit unit)
{
unit.Move(translation);
}
public override void undo(Unit unit)
{
unit.Move(-translation);
}
}
public class CommandPattern : MonoBehaviour
{
public Unit unit;
public bool isRun = true;
private Stack<Command> commands;
private float passTime;
// Start is called before the first frame update
void Start()
{
commands = new Stack<Command>();
passTime = 0f;
}
// Update is called once per frame
void Update()
{
if (isRun)
{
HandleCommands();
}
else
{
RollbackCommands();
}
}
void HandleCommands()
{
passTime += Time.deltaTime;
Command command = HandleInput();
if (command != null) {
commands.Push(command);
command.execute(unit);
}
}
void RollbackCommands()
{
passTime -= Time.deltaTime;
if (commands.Count > 0 && passTime < commands.Peek().Time)
{
commands.Pop().undo(unit);
}
}
Command HandleInput()
{
if (Input.GetKey(KeyCode.W))
return new MoveCommand(new Vector3(0, Time.deltaTime, 0), passTime);
if (Input.GetKey(KeyCode.S))
return new MoveCommand(new Vector3(0, -Time.deltaTime, 0), passTime);
if (Input.GetKey(KeyCode.A))
return new MoveCommand(new Vector3(-Time.deltaTime, 0, 0), passTime);
if (Input.GetKey(KeyCode.D))
return new MoveCommand(new Vector3(Time.deltaTime, 0, 0), passTime);
return null;
}
}
PS. 腾讯引擎技术中心的一位技术牛人写过一篇用命令模式封装多线程调用的blog,命令模式的典型应用场景。
PS. 我的设计模式系列blog,《设计模式》专栏,通过简单的示例演示设计模式,对于初学者很容易理解入门。深入学习请看GoF的《设计模式》。