یاد بگیرید که چگونه از الگوی Command برای کپسوله کردن درخواست ها به عنوان اشیا استفاده کنید، که می توانید به تنهایی یا به ترتیب در برنامه های جاوا خود اجرا کنید.
- الگوی فرمان چیست؟
- الگوی فرمان در JDK
- موتورسیکلت من را بران! الگوی فرمان در رابط خودرو
- اجرای دستورات در الگوی فرمان
- زمان استفاده از الگوی فرمان
- چه چیزی را در مورد الگوی فرمان به خاطر بسپارید
یکی از بزرگترین چالشهای ما بهعنوان توسعهدهندگان نرمافزار، سازماندهی کدمان است تا گسترش و نگهداری آن آسانتر باشد. الگوی Command با کپسوله کردن تمام داده های مورد نیاز برای انجام یک عمل در یک شی Command
به ما کمک می کند این کار را انجام دهیم.
شما ممکن است الگوی Command را تشخیص دهید زیرا ما همیشه از آن در زندگی روزمره خود استفاده می کنیم. یک مثال خوب استفاده از یک دستگاه کنترل از راه دور برای روشن کردن تلویزیون، تعویض کانال، افزایش صدا و غیره است. هر یک از این اقدامات در دستگاه کنترل از راه دور محصور شده است.
نکته دیگری که در مورد همه این اقدامات باید به آن توجه داشت این است که آنها برگشت پذیر هستند: می توانید تلویزیون را روشن کنید و همچنین می توانید آن را خاموش کنید. علاوه بر این، برخی از اقدامات باید به ترتیب انجام شوند: قبل از اینکه بتوانید صدا را افزایش دهید، باید تلویزیون را روشن کنید.
در این چالش کد جاوا، با الگوی طراحی Command آشنا خواهید شد و چندین نمونه از الگو را در عمل مشاهده خواهید کرد. همچنین درباره نحوه اجرای الگوی فرمان دو اصل اصلی SOLID. این دو اصل عبارتند از اصل مسئولیت تکی، که بیان می کند که یک کلاس باید فقط یک کار داشته باشد، و اصل باز-بسته، که بیان می کند که اشیا یا موجودیت ها باید باشند. برای پسوند باز است اما برای اصلاح بسته است.
الگوی فرمان چیست؟
الگوی Command یکی از ۲۳ الگوی طراحی است که با طراحی گروه چهار الگو. فرمان یک الگوی طراحی رفتاری است، به این معنی که هدف آن اجرای یک عمل در یک الگوی کد خاص است.
چهار نوع الگوی طراحی
برای مروری بر چهار نوع الگوی طراحی به معرفی الگوهای طراحی مراجعه کنید.
زمانی که برای اولین بار معرفی شد، الگوی Command گاهی اوقات به عنوان Callbacks برای جاوا توضیح داده می شد. در حالی که جاوا ۸ به عنوان یک الگوی طراحی شی گرا شروع شد، عبارات لامبدا را معرفی کرد که امکان اجرای شی-عملکردی الگوی فرمان. این مقاله شامل مثالی با استفاده از عبارت لامبدا در الگوی فرمان است.
مانند همه الگوهای طراحی، بسیار مهم است که بدانید چه زمانی باید الگوی Command را اعمال کنید و چه زمانی الگوی دیگری ممکن است بهتر باشد. استفاده از الگوی طراحی اشتباه برای یک مورد استفاده میتواند کد شما را پیچیدهتر کند، نه کمتر.
الگوی فرمان در JDK
ما میتوانیم نمونههای زیادی از الگوی Command را در کیت توسعه جاوا و در اکوسیستم جاوا پیدا کنیم. یک مثال محبوب استفاده از رابط کاربردی Runnable
با کلاس Thread
است. دیگری مدیریت رویدادها با ActionListener
است. بیایید هر دوی این مثال ها را بررسی کنیم.
کد مثال را دریافت کنید
کد فرمان را دریافت کنید نمونه های الگو نشان داده شده در این مقاله.
الگوی فرمان با Thread و Runnable
قابل اجرا
واسطی است که شامل روش run()
است. قطعه کد زیر امضای روش run()
را نشان میدهد. همانطور که می بینید، امکان ارسال یک دستور در روش run()
وجود دارد:
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Thread
پر استفاده ترین کلاسی است که Runnable
دریافت می کند. بیایید ببینیم چگونه می توانیم دستوری را به کلاس Thread
ارسال کنیم:
Runnable command = () -> System.out.println("Executing command!");
Thread thread = new Thread(command); // Setting command
thread.start();
در این کد، رفتار فرمان را در متد run()
با عبارت lambda پیاده سازی می کنیم. به جای لامبدا، میتوانیم از یک کلاس داخلی ناشناس استفاده کنیم، که یک کلاس بینام است که روش Runnable
و run()
را پیادهسازی میکند. اما این رویکرد کد را پرمعناتر می کند. استفاده از لامبدا مختصرتر و خواندن آسان تر است.
سپس دستور را به کلاس Thread
میدهیم. در نهایت با فراخوانی متد start()
دستور را اجرا می کنیم.
خروجی که میتوانیم از این کد انتظار داشته باشیم در اینجا آمده است:
Executing command!
الگوی فرمان با ActionListener
یک مثال خوب دیگر در JDK رابط ActionListener
است. من می دانم که این یک رابط قدیمی است، اما به عنوان مثال مناسب است.
در کد زیر، یک JFrame
و یک JButton
ایجاد می کنیم. سپس با فراخوانی متد addActionListener()
عمل را در دکمه تنظیم می کنیم. در این مورد، ما فقط متن را از “Click me” به “Clicked” تغییر می دهیم. سپس، دکمه را به قاب اضافه می کنیم و کادر را با دکمه:
نشان می دهیم
JFrame frame = new JFrame();
JButton button = new JButton("Click Me");
button.addActionListener(e -> button.setText("Clicked!")); // Command implementation
frame.add(button);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
شکل ۱ نتایج این کد را پس از کلیک روی دکمه نشان می دهد.
شکل ۱. ActionListener در حال عمل.
موتور سیکلت من را بران! الگوی فرمان در رابط خودرو
اکنون که نمونه هایی از الگوی Command را در JDK دیدید، بیایید الگوی خود را ایجاد کنیم. ابتدا به نمودار کلاس در شکل ۲ نگاهی بیندازید.
شکل ۲. نموداری از الگوی فرمان برای رابط خودرو.
سه بخش در نمودار وجود دارد که توضیح خواهم داد.
فرمان
کلاس پایه برای الگوی Command رابط Command
است. ما هر زمان که بخواهیم دستوری را اجرا یا برگردانیم از این رابط استفاده می کنیم:
public interface Command {
void execute();
void revert();
}
گیرنده
بعد، باید کلاسی را ایجاد کنیم که رفتار اجرای دستور را داشته باشد. ما با رابط Vehicle
شروع می کنیم، سپس کلاس های Motorcycle
و Truck
را برای پیاده سازی آن ایجاد می کنیم:
public interface Vehicle {
void start();
void stop();
void accelerate();
}
public class Motorcycle implements Vehicle {
@Override
public void start() {
System.out.println("Starting motorcycle...");
}
@Override
public void stop() {
System.out.println("Stopping motorcycle...");
}
@Override
public void accelerate() {
System.out.println("Accelerating motorcycle...");
}
}
public class Truck implements Vehicle {
@Override
public void start() {
System.out.println("Starting truck...");
}
@Override
public void stop() {
System.out.println("Stopping truck...");
}
@Override
public void accelerate() {
System.out.println("Accelerating truck...");
}
@Override
public void decelerate() {
System.out.println("Decelerating truck...");
}
}
همچنین توجه داشته باشید که رابط Vehicle
کد را انعطافپذیرتر و تغییر آن آسانتر میکند: ما به راحتی میتوانیم وسیله نقلیه دیگری مانند Car
اضافه کنیم که Vehicle< را پیادهسازی میکند. /code> رابط. این قسمت از الگوی Command یک مثال عالی از اصل باز-بسته جامد است. (به یاد داشته باشید که این اصل بیان می کند که اشیا یا موجودیت ها باید قابل توسعه باشند.)
فراخوان
اکنون، ما رفتار Motorcycle
و Truck
را داریم اما برای اجرای آن به یک کلاس نیاز داریم. در مورد ما، این کلاس GhostRider
خواهد بود. GhostRider
کلاسهای موتور سیکلت
و کامیون
را هدایت میکند.
GhostRider
دستور را در سازنده دریافت می کند و متد execute()
را از دستور به takeAction()
و فراخوانی می کند. متدهای revertAction()
:
public class GhostRider {
Command command;
public GhostRider(Command command){
this.command = command;
}
public void setCommand(Command command) {
this.command = command;
}
public void takeAction(){
command.execute();
}
public void revertAction() {
command.revert();
}
}
اجرای دستورات در الگوی فرمان
اکنون، اجازه دهید دستورات StartMotorcycle
، AccelerateMotorcycle
و StartAllVehicles
را ایجاد کنیم. هر فرمان رابط Command
را پیاده سازی می کند و Vehicle
را در سازنده دریافت می کند. سپس، متد مربوط به هر کلاس فرمان را از Vehicle
به متد execute()
فراخوانی می کند:
public class StartMotorcycle implements Command {
Vehicle vehicle;
public StartMotorcycle(Vehicle vehicle) {
this.vehicle = vehicle;
}
public void execute() {
vehicle.start();
}
@Override
public void revert() {
vehicle.stop();
}
}
public class AccelerateMotorcycle implements Command {
Vehicle vehicle;
public AccelerateMotorcycle(Vehicle vehicle){
this.vehicle = vehicle;
}
public void execute() {
vehicle.accelerate();
}
@Override
public void revert() {
vehicle.decelerate();
}
}
import java.util.List;
public class StartAllVehicles implements Command {
List<Vehicle> vehicles;
public StartAllVehicles(List<Vehicle> vehicles) {
this.vehicles = vehicles;
}
public void execute() {
vehicles.forEach(vehicle -> vehicle.start());
}
@Override
public void revert() {
vehicles.forEach(vehicle -> vehicle.stop());
}
}
دستورات را اجرا کنید
زمان اجرای دستورات ما فرا رسیده است! برای این کار، ابتدا کلاس Motorcycle
را که دارای رفتار Command
است نمونهسازی میکنیم، سپس آن را به هر اجرای Command
ارسال میکنیم.
توجه داشته باشید که ما همچنین از دستور StartAllVehicles
برای راهاندازی (و توقف) چندین وسیله نقلیه به طور همزمان استفاده میکنیم.
سپس، کلاس GhostRider
را نمونهسازی میکنیم که هر فرمان را اجرا میکند. در نهایت، روشهای takeAction()
و revertAction()
را فراخوانی میکنیم:
public class RideVehicle {
public static void main(String[] args) {
Vehicle motorcycle = new Motorcycle();
StartMotorcycle startCommand = new StartMotorcycle(motorcycle);
GhostRider ghostRider = new GhostRider(startCommand);
ghostRider.takeAction();
AccelerateMotorcycle accelerateCommand = new AccelerateMotorcycle(motorcycle);
ghostRider.setCommand(accelerateCommand);
ghostRider.takeAction();
ghostRider.revertAction();
Vehicle truck = new Truck();
List<Vehicle> vehicles = List.of(motorcycle, truck);
StartAllVehicles startAllVehicles = new StartAllVehicles(vehicles);
startAllVehicles.execute();
startAllVehicles.revert();
}
}
خروجی این کد در اینجا آمده است:
Starting motorcycle...
Accelerating motorcycle...
Decelerating motorcycle...
Starting motorcycle...
Starting truck...
Stopping motorcycle...
Stopping truck…
زمان استفاده از الگوی فرمان
یک قانون اساسی برای الگوهای طراحی این است که بدانید چه زمانی از آنها استفاده کنید. مهم نیست که یک الگو چقدر عالی است، پیاده سازی آن برای موارد استفاده اشتباه کد شما را بسیار بدتر می کند. در اینجا چند دستورالعمل برای استفاده از الگوی فرمان آمده است:
- شما دستورات متعددی دارید که باید به طور جداگانه بر اساس اصول SOLID طراحی تک مسئولیتی و طراحی باز-بسته اجرا شوند.
- شما باید دستورات برگشت پذیر ایجاد کنید، مانند افزودن و حذف یک مورد از سبد خرید.
- هر زمان که دستوری اجرا می شود باید بتوانید گزارش ایجاد کنید. هر دستور در الگوی Command کپسوله شده است، بنابراین ایجاد گزارش آسان است.
- شما باید بتوانید چندین فرمان را همزمان اجرا کنید. میتوانید به راحتی یک
صف
،List
یاSet
را به اجرای یک فرمان اضافه کنید و آنها را اجرا کنید.
یک مورد استفاده سازمانی برای الگوی فرمان
مورد استفاده توسعهیافته در اینجا الگوی Command را پیادهسازی میکند، اما این یک وضعیت واقعی نیست. برای استفاده رایج تر در برنامه های کاربردی سازمانی، به بحث من در مورد استفاده از الگوی فرمان برای اعمال تخفیف در سبد خرید شرکتی.
چه چیزی را در مورد الگوی فرمان به خاطر بسپارید
برای خلاصه کردن، موارد زیر را در مورد الگوی فرمان به خاطر بسپارید:
- اصول جامد طراحی تک مسئولیتی و طراحی باز-بسته را اعمال می کند.
- این رفتار دستورات را کپسوله میکند و از هم جدا میکند، که کد شما را توسعهپذیرتر میکند.
- در JDK با کلاس
Thread
و رابط هایRunnable
وActionListener
استفاده می شود. - رفتار دستورات را در یک اجرای
Command
محصور می کند. - به شما امکان می دهد دستورات واحد را اجرا و برگردانید.
- به شما امکان می دهد چندین فرمان را با هم اجرا و برگردانید.
پست های مرتبط
نحوه استفاده از الگوی Command در جاوا
نحوه استفاده از الگوی Command در جاوا
نحوه استفاده از الگوی Command در جاوا