การเขียนโปรแกรมในรูปแบบ command มีจุดประสงค์เพื่อแยกส่วนที่เป็นวิธีการทำงาน (business logic) ออกจากการเรียกใช้งาน หลักการคือซ่อนองค์ประกอบของสิ่งที่เกี่ยวข้องกับวิธีการทำไม่ว่าจะเป็นเมธอด พารามิเตอร์ หรือออบเจกต์ไว้ในออบเจกต์เดียว ส่วนการเรียกใช้งานจะทำผ่านอีกออบเจกต์หนึ่งซึ่งจะทำหน้าที่แค่เรียกใช้เมธอดที่กำหนดมาเพื่อทำงานนั้นๆเท่านั้น ออบเจกต์ที่เก็บส่วนที่เป็นวิธีการทำงานเราเรียกว่า receiver ส่วนออบเจกต์ที่เป็นคำสั่งจะแบ่งออกเป็น 2 ส่วนคือออบเจกต์ส่วนที่เป็นตัวคำสั่งซึ่งจะไม่มีการดำเนินการใดๆ (no business logic ) เรียกว่า command และออบเจกต์ที่เรียกใช้คำสั่งเรียกว่า invoke
ประโยชน์ของการเขียนโปรแกรมในรูปแบบนี้คือ เมื่อต้องมีการแก้ไขวิธีการทำงานก็จะทำการแก้ไขที่ receiver ที่เดียว ดังนั้นจะไม่กระทบกับโปรแกรมที่เรียกใช้งาน และสามารถแยกส่วนของการเรียกใช้คำสั่งออกจากส่วนของวิธีการทำงานได้อย่างเด็ดขาด
จากตัวอย่างด้านล่างจะเป็นรูปแบบการเขียนโปรแกรมแบบ command เพื่อสั่ง เปิด/ปิด หลอดไฟเริ่มจากการประกาศอินเตอร์เฟส Command ซึ่งจะมีเมธอดเดียวคือ execute() วัตถุประสงค์เพื่อเป็นกรอบของการเรียกใช้คำสั่ง (framework) เพื่อเอาไว้เรียกเมธอดที่ต้องการมาทำงานโดยต้องไม่มีรายละเอียดวิธีการทำงาน (business logic) อยู่ในคลาสนี้ นอกจากการใช้อินเตอร์เฟส เราอาจจะใช้คลาสแบบ abstarct หรือ คลาสธรรมดาก็ได้ แต่ให้ยึดตามวัตถุประสงค์
public interface Command {
void execute();
}
จากนั้นจึงประกาศคลาสที่เป็น concrete command คือ LightOnCommand และ LightOffCommand ซึ่งสืบทอดมาจากอินเตอร์เฟส Command วัตถุประสงค์เพื่อใช้เป็นคำสั่งสำหรับเรียกใช้งานโดยซ่อนส่วนที่ติดต่อกับวิธีการทำงานจริงๆเอาไว้โดยการกำหนดฟิลด์ที่เก็บออบเจกต์ของ receiver ให้เป็นแบบ private ส่วนตัวคำสั่งหรือเมธอดที่จะให้เรียกใช้งานได้จะกำหนดเป็นแบบ public และโอเวอร์ไรด์เมธอด execute() เพื่อเรียกใช้เมธอดที่เป็นวิธีการทำงานจริงๆของ receiver ซึ่งทั้งคลาส command คลาส LightOnCommand และ LightOffCommand เรารียกว่าส่วน command
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.lightOn();
}
}
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.lightOff();
}
}
ถัดมาคือการประกาศคลาส Light ซึ่งจะเป็นคลาสที่ระบุวิธีการทำงานที่เกิดขึ้นจริงๆ (business logic) เมื่อมีการเรียกใช้เมธอด ซึ่งคลาส Light คือส่วนที่เราเรียกว่า receiver
public class Light {
public void lightOn() {
System.out.println(“Turn on Light”);
}
public void lightOff() {
System.out.println(“Turn off Light”);
}
}
และสุดท้ายคือการสร้างคลาสที่เป็นส่วนที่เรียกใช้คำสั่ง (invoke) ซึ่งเป็นคลาสที่จะกำหนดว่าจะเรียกใช้คำสั่งอย่างไร
public class Controller {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
ในการใช้งานจะเป็นการใช้งานผ่านคลาสที่เป็นส่วนที่เรียกใช้คำสั่ง (invoke) ซึ่งสามารถสรุปขั้นตอนการใช้งานได้ง่ายๆว่า 1. สร้างออบเจกต์ของคลาสที่เป็นส่วนที่เรียกใช้คำสั่งซึ่งในที่นี้คือคลาส Controller 2. สร้างคำสั่งโดยระบุชนิดของออบเจกต์เป็น command และสร้างออบเจกต์ที่คำสั่งเฉพาะของแต่ละงาน และ 3. เรียกใช้คำสั่งผ่านออบเจกต์ invoke
public class HomeAutomationDemo {
public static void main(String[] args) {
Controller controller = new Controller();
Light light = new Light();
Command lightsOn = new LightOnCommand(light);
Command lightsOff = new LightOffCommand(light);
controller.setCommand(lightsOn);
controller.executeCommand();
controller.setCommand(lightsOff);
controller.executeCommand();
}
}

จากรูปด้านบน ด้านซ้ายเป็นการเรียกใช้ออบเจกต์จากคลาส ส่วนด้านขวาเป็นการใช้รูปแบบ command การเขียนโปรแกรมในรูปแบบ command เป็น 1 ใน 12 รูปแบบการเขียนโปรแกรมในกลุ่มรูปแบบ behavioral ซึ่งจะใส่ใจกับการโต้ตอบกันระหว่างออบเจกต์เป็นหลัก
เราสามารถใช้รูปแบบการเขียนโปรแกรมแบบ command ร่วมกับ
- การบรรจุคำสั่งลงใน queue และเรียกมาทำงานในภายหลัง : เพราะออบเจกต์ส่วนที่เป็นการเรียกใช้คำสั่งกับออบเจกต์ที่ทำตามคำสั่งแยกขาดจากกันทำให้เราสามารถเก็บออบเจกต์ที่เป็นการเรียกใช้คำสั่งไปเข้า queue เพื่อเรียกมาใช้งานตามลำดับ
- การรองรับการทำ undo / redo : เพราะออบเจกต์ส่วนที่เป็นการเรียกใช้คำสั่งกับออบเจกต์ที่ทำตามคำสั่งแยกขาดจากกันทำให้เราสามารถเก็บลำดับของออบเจกต์ที่เป็นการเรียกใช้คำสั่งไว้เพื่ออ้างอิงลำดับการทำงานหากต้องการย้อนการขั้นตอนการทำคำสั่ง ซึ่งในกรณีนี้เราต้องสร้างเมธอดที่มีวิธีการทำงานที่ย้อนกลับผลลัพธ์จากทำคำสั่งต่างๆใน receiver ด้วย
- การเก็บประวัติการทำงานของคำสั่ง : เพราะออบเจกต์ส่วนที่เป็นการเรียกใช้คำสั่งกับออบเจกต์ที่ทำตามคำสั่งแยกขาดจากกันทำให้เราสามารถเก็บลำดับของออบเจกต์ที่เป็นการเรียกใช้คำสั่งไว้เพื่ออ้างอิงได้
- การเก็บลำดับการทำงานลงในดิสก์ : เพราะออบเจกต์ส่วนที่เป็นการเรียกใช้คำสั่งกับออบเจกต์ที่ทำตามคำสั่งแยกขาดจากกันทำให้เราสามารถเก็บลำดับของออบเจกต์ที่เป็นการเรียกใช้คำสั่งลงในไฟล์ได้
- การนำคำสั่งหลายๆคำสั่งมาประกอบกันเป็นคำสั่งเดียวที่เรียกว่า macro : เพราะออบเจกต์ส่วนที่เป็นการเรียกใช้คำสั่งกับออบเจกต์ที่ทำตามคำสั่งแยกขาดจากกันทำให้เราสามารถเก็บลำดับการทำงานของออบเจกต์ที่เป็นชุดของคำสั่งได้
ตัวอย่างการใช้การเขียนโปรแกรมในรูปแบบ command กับแอพพลิเคชั่น
- ใช้เพื่อควบคุมการดำเนินการเมื่อมีการกดปุ่มหรือเมนูในรูปแบบการติดต่อผู้ใช้งานแบบ GUI เช่น ในการใช้งานแพคเกจ Swing จะมีอินเตอร์เฟส Action กรอบของการเรียกใช้คำสั่ง (เทียบได้กับอินเตอร์เฟส command ในตัวอย่างด้านบน) ซึ่งนอกจากจะเป็นการปฏิบัติตามคำสั่งที่ต้องการแล้ว ยังสามารถเพิ่มเติมการใช้ ไอคอน(icon) คีย์ลัด(shortcut) ข้อความช่วยเหลือ(tooltip text) หรือความสามารถอื่นๆได้ด้วย
- การใช้งานเครือข่าย (networking) เช่น ส่งอ็อบเจ็กต์การเรียกใช้คำสั่งทั้งหมดผ่านเครือข่ายเพื่อดำเนินการบนเครื่องอื่น: ตัวอย่างเช่น ส่งให้ผู้เล่นเกมส์ใช้ในการสั่งดำเนินการจากเครื่องของผู้เล่นเกมส์
- ใช้เก็บลำดับการทำงานเพื่อให้สามารถย้อนคำสั่งที่ทำไปได้ เช่น การทำ undo ของการทำกิจกรรมต่างๆ หรือการทำ roll back ในการติดตั้งโปรแกรมหรือการปรับปรุงฐานข้อมูล เป็นต้น
- ในการเขียนโปรแกรมแบบหลายเธรด (miltithread) เราสามารถการแยกส่วนของตัวเรียกใช้งานคำสั่ง (invoke) กับตัวที่ทำงาน (receiver) ให้ทำงานคนละเธรด โดยตัวเรียกใช้งานคำสั่งจะเอาคำสั่งเข้าคิวไว้และส่งให้ตัวที่ทำงานทำเมื่อตัวที่ทำงานเสร็จงานในแต่ละงาน
ตัวอย่างด้านล่างเป็นอีกหนึ่งตัวอย่างในการเขียนโปรแกรมด้วยรูปแบบ command
import java.util.Scanner;
class Client {
public static void main(String[] args) {
Controller controller = new Controller();
TV tv = new TV();
int[] channelList = new int[3];
Scanner scanner = new Scanner(System.in);
for (int i = 0; i < 3; i++) {
channelList[i] = scanner.nextInt();
}
Command turnOnTV = new TurnOnCommand(tv);
controller.setCommand(turnOnTV);
controller.executeCommand();
Command changeChannel;
for (int i = 0; i < 3; i++) {
Channel channel = new Channel(tv,channelList[i]);
changeChannel = new ChangeChannelCommand(channel);
controller.setCommand(changeChannel);
controller.executeCommand();
}
Command turnOffTV = new TurnOffCommand(tv);
controller.setCommand(turnOffTV);
controller.executeCommand();
}
}
class TV {
Channel channel;
void turnOn() {
System.out.println("Turning on the TV");
setChannel(new Channel(this, 0));
}
void turnOff() {
System.out.println("Turning off the TV");
}
void setChannel(Channel channel) {
this.channel = channel;
}
}
class Channel {
private TV tv;
private int channelNumber;
Channel(TV tv, int channelNumber) {
this.tv = tv;
this.channelNumber = channelNumber;
}
void changeChannel() {
tv.setChannel(this);
System.out.println("Channel was changed to " + channelNumber);
}
}
interface Command {
void execute();
}
class TurnOnCommand implements Command {
private TV tv;
TurnOnCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.turnOn();
}
}
class TurnOffCommand implements Command {
private TV tv;
TurnOffCommand(TV tv) {
this.tv = tv;
}
@Override
public void execute() {
tv.turnOff() ;
}
}
class ChangeChannelCommand implements Command {
private Channel channel;
ChangeChannelCommand(Channel channel) {
this.channel = channel;
}
@Override
public void execute() {
channel.changeChannel();
}
}
class Controller {
private Command command;
void setCommand(Command command) {
this.command = command;
}
void executeCommand() {
command.execute();
}
}