当前位置:网站首页>Command mode - unity

Command mode - unity

2022-07-07 19:13:00 Just be interesting

Command mode

Command mode is an object behavior mode , adopt The request between the requester and the performer is extracted and encapsulated into an object , Thus, the responsibility of sending the request is separated from the responsibility of executing the request . The requester and the executor communicate through the command object , This allows the command object to be stored , management , Deliver, etc .

Command mode is a very common mode in behavioral mode , It is also very important in game development . By managing and storing a large number of commands , It ensures the order and unity of commands . When using software , We often use undo , How the software performs undo , It is obviously to save every step of your operation , Restore by reading each step . This is the command mode , Each step is a command .

for example , Remote control and TV , The remote control is the requestor , Television is the executor , Who is the order , The buttons on the remote control are commands . Restaurants usually have a menu for customers to choose from , The waiter passes the menu to the chef , The chef is responsible for cooking . The dish selected in the menu is a command , The waiter acts as a middleman ( Belongs to the caller ), He is not responsible for carrying out , Responsible for delivering and managing these menus ( command ), And the menu will eventually be taken by the chef , And start the mission ( The chef is the executor ). How vivid , This is the wisdom of life .

structure

 Insert picture description here
explain

  • Abstract command (Command) - Generally, there is only one interface to execute command methods ( There can also be a cancellation method , Of course, if necessary )
  • Specific commands (Concrete Command)- Concrete implementation classes of abstract commands , Does not implement the method itself , As the carrier of implementer parameters , Delegate work to implementers .
  • Implementer (Receiver)- A class that implements business logic , Is the class that finally completes the method , Almost all objects can act as implementers .
  • caller (Invoker)- There are multiple command objects stored , No direct access to implementers , Executing requests through command objects .( The command object itself is not created , Nor does it execute business methods ), It mainly manages command objects , Store , Execution, etc .

Realization

This example may be tedious , But in general, it is not too complicated .
Mainly to achieve recovery and revoke And so on .
Drive by command UI Move

Move enum

    public enum MoveDirection
    {
    
        Left,
        Right,
        Up,
        Down,
    }

UI Move - Implementer ( The singleton pattern , Just one copy )

    public class UIMove
    {
    
        private static UIMove _instacne = new UIMove();
        // Moving distance 
        private const float MoveDistance = 100f;
        
        public static UIMove Instacne => _instacne;
        
        private UIMove() {
     }
        
        // Move 
        public void Move(RectTransform rt, MoveDirection direction)
        {
    
            Vector3 position = rt.position;
            rt.position = direction switch
            {
    
                MoveDirection.Left => new Vector3(position.x - MoveDistance, position.y, position.z),
                MoveDirection.Right => new Vector3(position.x + MoveDistance, position.y, position.z),
                MoveDirection.Up => new Vector3(position.x, position.y + MoveDistance, position.z),
                MoveDirection.Down => new Vector3(position.x, position.y - MoveDistance, position.z),
                _ => throw new ArgumentOutOfRangeException(nameof(direction)),
            };
        }
    }

The command interface - Abstract command

    public interface ICommand
    {
    
        //  perform 
        void Execute();
        //  revoke 
        void Undo();
        //  Command to convert string 
        string ToString();
    }

Mobile command - Specific commands

    public class MoveCommand : ICommand
    {
    
        // Keep the only one 
        private readonly UIMove _receiver;
        private readonly RectTransform _transform;
        private readonly MoveDirection _direction;

        public MoveCommand(MoveDirection direction, RectTransform transform)
        {
    
            _direction = direction;
            _transform = transform;
            _receiver = UIMove.Instacne; // A single example 
        }

        public void Execute() => _receiver.Move(_transform, _direction);

        public void Undo()
        {
    
            switch (_direction)
            {
    
                case MoveDirection.Left:
                    _receiver.Move(_transform, MoveDirection.Right);
                    break;
                case MoveDirection.Right:
                    _receiver.Move(_transform, MoveDirection.Left);
                    break;
                case MoveDirection.Up:
                    _receiver.Move(_transform, MoveDirection.Down);
                    break;
                case MoveDirection.Down:
                    _receiver.Move(_transform, MoveDirection.Up);
                    break;
                default:
                    throw new ArgumentOutOfRangeException(nameof(_direction));
            }
        }

        public override string ToString()
        {
    
            return _direction.ToString();
        }
    }

UI Move call - caller

    public class UIMoveInvoker
    {
    
        private List<ICommand> _commands;
        private int _index = -1;

        public int Index => _index;
        public List<ICommand> CommandList => _commands;

        public UIMoveInvoker()
        {
    
            _commands = new List<ICommand>();
        }
		
		// Execute the move command 
        public void Move(ICommand command)
        {
    
            command.Execute();
			
			// If the command is not the last , Then delete all the following commands 
            if (_index < _commands.Count - 1)
            {
    
                _commands.RemoveRange(_index + 1, _commands.Count - _index - 1);
            }
            _commands.Add(command);
            _index++;
        }
		
		// Recovery operation 
        public void ReDo()
        {
    
            if (_index >= _commands.Count - 1) return;

            _index++;
            _commands[_index].Execute();
        }
		 
		// Cancel the operation  
        public void UnDo()
        {
    
            if (_index < 0) return;

            _commands[_index].Undo();
            _index--;
        }
    }

client ( Use GUI As a visualization )

    public class CommandExample : MonoBehaviour
    {
    
        [SerializeField] private GUIStyle style;
        [SerializeField] private RectTransform rectTransform;
        private UIMoveInvoker _invoker;

        private void Awake()
        {
    
            _invoker = new UIMoveInvoker();
        }

        private void Update()
        {
    
            if (Input.GetKeyDown(KeyCode.W)) _invoker.Move(new MoveCommand(MoveDirection.Up, rectTransform));
            else if (Input.GetKeyDown(KeyCode.S)) _invoker.Move(new MoveCommand(MoveDirection.Down, rectTransform));
            else if (Input.GetKeyDown(KeyCode.A)) _invoker.Move(new MoveCommand(MoveDirection.Left, rectTransform));
            else if (Input.GetKeyDown(KeyCode.D)) _invoker.Move(new MoveCommand(MoveDirection.Right, rectTransform));
            else if (Input.GetKeyDown(KeyCode.E)) _invoker.UnDo();
            else if (Input.GetKeyDown(KeyCode.R)) _invoker.ReDo();
        }

        private void OnGUI()
        {
    
            var list = _invoker.CommandList;
            var index = _invoker.Index;
            
            GUILayout.BeginVertical();
            GUILayout.Label((index == -1 ? ">> " : "") + "Start", style);

            for (int i = 0; i < list.Count; i++)
            {
    
                if (i == index) GUILayout.Label(">> " + list[i].ToString(), style);
                else GUILayout.Label(list[i].ToString(), style);
            }
            
            GUILayout.EndVertical();
        }
    }

Running results
 Insert picture description here

explain
 Insert picture description here

Application scenarios

  • When the system needs to support commands Revocation and reinstatement when , You can use command mode to store commands .
  • When it is necessary to Operation is parameterized when , You can use command mode
  • Need to put Requestor and executor are decoupled , Command mode allows the caller not to interact directly .
  • When the system needs to perform a set of operations , Command mode can Define macro commands to implement this function .( You can use composite mode to complete a composite command )

Advantages and disadvantages

advantage

  • Single responsibility , The caller and implementer are separated .
  • When adding a new command , There is no need to modify the client , It satisfies the open close principle
  • Undo and restore functions can be realized
  • Macro commands can be implemented

shortcoming

  • Generate a large number of command classes , Complicate the system

Relationship with other models

  • Prototype mode matches command mode , You can save the command
  • Combination mode and command mode , You can use a combination command
  • The difference between policy mode and command mode , Both are through parameterized objects . Policy mode focuses on context algorithm switching , Describes the different ways in which the purpose is performed . Command mode is to parameterize the operation into commands . By parameterizing the command , To delay the call , Keep records , Send commands, etc .

... Because I haven't finished learning design patterns yet , Other models will not be compared , First write

​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

原网站

版权声明
本文为[Just be interesting]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207071515233710.html