One way to implement undo/redo is to store commands in a doubly linked list, where whenever you do an action, you store its command as the redo, and you store a matching command that sets the state back to what it was in the undo command field. Then, you can have infinite undos and redos by simply moving backward and forward through the links.
Note that the AS3 framework, Robotlegs, was based on the Command pattern, and because AS3 supported events where things could listen for events without needing to directly be connected to the sender and functions could be injected through constructors or properties, Views could cause commands to fire by simply calling a function that dispatched an event on a common event bus. Then the View would not have to have any references to the command infrastructure built in. This could also be done with ReduxJS (in the mapDispatchToProps version). I think Java is kind of weird in allowing functions to be passed and decoupled events, but I thought I'd throw this out for the front end devs who might read this.