The command pattern packages instructions in structures that implement a shared `Command` trait. Each command acts on a receiver, separating what executes from the target and from when or in what order it executes. section 5.6 section 5.8
A command’s `execute` method can return `Result<(), Error>` to propagate failures. Concrete command types hold the receiver and any needed data; clients can store them behind `Box<dyn Command>` and execute them in sequence. section 5.6.1 section 5.6.2
File commands
A file handle can serve as the receiver for `ReadFile` and `WriteFile` commands. A client places both in a vector of boxed command trait objects and executes them in order. The write example appends content; because it is not idempotent, repeated runs can change the file again. section 5.6.2
Commands can also support forward and reverse operations, as in undo/redo, but that requires tracking state and making operations idempotent. The simple file example does not provide that; consider whether this widely used but loosely specified pattern is worthwhile for the task. section 5.6 section 5.6.2
Listing 5.15 Command trait definition
trait Command {
fn execute(&self) -> Result<(), Error>;
}
See the minimal `Command` trait and its result type. section 5.6.1
Listing 5.18 Client implementation for command pattern
use std::fs::File;
use std::io::{BufRead, BufReader, Error, Seek, Write};
fn main() -> Result<(), Error> {
let file = File::options() #1
.read(true)
.write(true)
.create(true)
.append(true)
.open("file.txt")?;
let commands: Vec<Box<dyn Command>> = vec![ #2
ReadFile::new(file.try_clone()?), #3
WriteFile::new(
"file content\n".into(), file.try_clone()? #4
),
ReadFile::new(file.try_clone()?),
];
for command in commands { #5
command.execute()?;
}
Ok(())
}
See how a client stores and executes concrete commands through boxed trait objects. section 5.6.2




