命令模式

2023-10-10  本文已影响0人  全新的饭

概念

命令是具现化的方法调用。
命令模式是一种回调的面向对象实现。
每条命令为1个类的实例,从而可以被传递、存储、重复利用。

例子

制作移动命令,按“wasd”时控制角色移动,按空格键时回退角色移动。


示意图.gif

Command.cs
每个命令有2个方法:Execute、Undo。
当前实现1个具体的命令MoveCommand来控制IMoveExecutor移动(Move)

using UnityEngine;
public abstract class Command
{
    public abstract void Execute(IExecutor executor);
    public abstract void Undo(IExecutor executor);
}

public class MoveCommand : Command
{
    private Vector3 _moveOffset;
    public MoveCommand(Vector3 moveOffset)
    {
        _moveOffset = moveOffset;
    }

    public override void Execute(IExecutor executor)
    {
        if (executor is IMoveExecutor moveExecutor)
        {
            moveExecutor.Move(_moveOffset);
        }
    }

    public override void Undo(IExecutor executor)
    {
        if (executor is IMoveExecutor moveExecutor)
        {
            moveExecutor.Move(_moveOffset * -1);
        }
    }
}

RoleMoveCtr.cs
实现IMoveExecutor,控制实际的transform移动。

using UnityEngine;

public interface IExecutor
{

}

interface IMoveExecutor : IExecutor
{
    void Move(Vector3 offset);
}

// 控制角色移动,需挂在要移动的transform上。
public class RoleMoveCtr : MonoBehaviour, IMoveExecutor
{
    private void Start()
    {
        Init();
    }
    private void OnDestroy()
    {
        MyDestroy();
    }

    private void Init()
    {

    }

    private void MyDestroy()
    {

    }

    public void Move(Vector3 offset)
    {
        transform.Translate(offset);
    }
}

CommandTest.cs
测试流程:接收输入生成并执行命令、或反向执行已有命令(实现 撤销移动 的操作)

using System.Collections.Generic;
using UnityEngine;

public class CommandTest : MonoBehaviour
{
    [SerializeField]
    private RoleMoveCtr _mover;
    [SerializeField]
    private float _moveSpeed;

    private Stack<Command> _commands;

    private void Start()
    {
        Init();
    }

    private void Update()
    {
        MyUpdate();
    }

    private void OnDestroy()
    {
        MyDestroy();
    }

    private void Init()
    {
        _commands = new Stack<Command>();
    }

    private void MyUpdate()
    {
        if (Input.GetKey(KeyCode.Space))
        {
            if (_commands.Count > 0)
            {
                _commands.Pop().Undo(_mover);
            }
        }
        else
        {
            Vector3 moveOffset = Vector3.zero;
            if (Input.GetKey(KeyCode.W))
            {
                moveOffset = new Vector3(0, Time.deltaTime, 0);
            }
            else if (Input.GetKey(KeyCode.S))
            {
                moveOffset = new Vector3(0, -1 * Time.deltaTime, 0);
            }
            else if (Input.GetKey(KeyCode.A))
            {
                moveOffset = new Vector3(-1 * Time.deltaTime, 0, 0);
            }
            else if (Input.GetKey(KeyCode.D))
            {
                moveOffset = new Vector3(Time.deltaTime, 0, 0);
            }
            if (moveOffset != Vector3.zero)
            {
                Command cmd = new MoveCommand(moveOffset * _moveSpeed);
                _commands.Push(cmd);
                cmd.Execute(_mover);
            }
        }
    }

    private void MyDestroy()
    {
        _commands.Clear();
        _commands = null;
    }
}
上一篇 下一篇

猜你喜欢

热点阅读