۲۹ شهریور ۱۴۰۳

Techboy

اخبار و اطلاعات روز تکنولوژی

نحوه استفاده از الگوی Command در جاوا

یاد بگیرید که چگونه از الگوی Command برای کپسوله کردن درخواست ها به عنوان اشیا استفاده کنید، که می توانید به تنهایی یا به ترتیب در برنامه های جاوا خود اجرا کنید.

یاد بگیرید که چگونه از الگوی Command برای کپسوله کردن درخواست ها به عنوان اشیا استفاده کنید، که می توانید به تنهایی یا به ترتیب در برنامه های جاوا خود اجرا کنید.

یکی از بزرگ‌ترین چالش‌های ما به‌عنوان توسعه‌دهندگان نرم‌افزار، سازمان‌دهی کدمان است تا گسترش و نگهداری آن آسان‌تر باشد. الگوی Command با کپسوله کردن تمام داده های مورد نیاز برای انجام یک عمل در یک شی Command به ما کمک می کند این کار را انجام دهیم.

شما ممکن است الگوی Command را تشخیص دهید زیرا ما همیشه از آن در زندگی روزمره خود استفاده می کنیم. یک مثال خوب استفاده از یک دستگاه کنترل از راه دور برای روشن کردن تلویزیون، تعویض کانال، افزایش صدا و غیره است. هر یک از این اقدامات در دستگاه کنترل از راه دور محصور شده است.

نکته دیگری که در مورد همه این اقدامات باید به آن توجه داشت این است که آنها برگشت پذیر هستند: می توانید تلویزیون را روشن کنید و همچنین می توانید آن را خاموش کنید. علاوه بر این، برخی از اقدامات باید به ترتیب انجام شوند: قبل از اینکه بتوانید صدا را افزایش دهید، باید تلویزیون را روشن کنید.

در این چالش کد جاوا، با الگوی طراحی Command آشنا خواهید شد و چندین نمونه از الگو را در عمل مشاهده خواهید کرد. همچنین درباره نحوه اجرای الگوی فرمان دو اصل اصلی SOLID. این دو اصل عبارتند از اصل مسئولیت تکی، که بیان می کند که یک کلاس باید فقط یک کار داشته باشد، و اصل باز-بسته، که بیان می کند که اشیا یا موجودیت ها باید باشند. برای پسوند باز است اما برای اصلاح بسته است.

الگوی فرمان چیست؟

الگوی Command یکی از ۲۳ الگوی طراحی است که با طراحی گروه چهار الگو. فرمان یک الگوی طراحی رفتاری است، به این معنی که هدف آن اجرای یک عمل در یک الگوی کد خاص است.

چهار نوع الگوی طراحی

برای مروری بر چهار نوع الگوی طراحی به معرفی الگوهای طراحی مراجعه کنید.

زمانی که برای اولین بار معرفی شد، الگوی Command گاهی اوقات به عنوان Callbacks برای جاوا توضیح داده می شد. در حالی که جاوا ۸ به عنوان یک الگوی طراحی شی گرا شروع شد، عبارات لامبدا را معرفی کرد که امکان اجرای شی-عملکردی الگوی فرمان. این مقاله شامل مثالی با استفاده از عبارت لامبدا در الگوی فرمان است.

مانند همه الگوهای طراحی، بسیار مهم است که بدانید چه زمانی باید الگوی Command را اعمال کنید و چه زمانی الگوی دیگری ممکن است بهتر باشد. استفاده از الگوی طراحی اشتباه برای یک مورد استفاده می‌تواند کد شما را پیچیده‌تر کند، نه کمتر.

ECMAScript 2022 عناصر کلاس را برکت می دهد، سطح بالا در انتظار است

الگوی فرمان در 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.

شکل ۱. 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…

زمان استفاده از الگوی فرمان

یک قانون اساسی برای الگوهای طراحی این است که بدانید چه زمانی از آنها استفاده کنید. مهم نیست که یک الگو چقدر عالی است، پیاده سازی آن برای موارد استفاده اشتباه کد شما را بسیار بدتر می کند. در اینجا چند دستورالعمل برای استفاده از الگوی فرمان آمده است:

  1. شما دستورات متعددی دارید که باید به طور جداگانه بر اساس اصول SOLID طراحی تک مسئولیتی و طراحی باز-بسته اجرا شوند.
  2. شما باید دستورات برگشت پذیر ایجاد کنید، مانند افزودن و حذف یک مورد از سبد خرید.
  3. هر زمان که دستوری اجرا می شود باید بتوانید گزارش ایجاد کنید. هر دستور در الگوی Command کپسوله شده است، بنابراین ایجاد گزارش آسان است.
  4. شما باید بتوانید چندین فرمان را همزمان اجرا کنید. می‌توانید به راحتی یک صف، List یا Set را به اجرای یک فرمان اضافه کنید و آنها را اجرا کنید.

یک مورد استفاده سازمانی برای الگوی فرمان

مورد استفاده توسعه‌یافته در اینجا الگوی Command را پیاده‌سازی می‌کند، اما این یک وضعیت واقعی نیست. برای استفاده رایج تر در برنامه های کاربردی سازمانی، به بحث من در مورد استفاده از الگوی فرمان برای اعمال تخفیف در سبد خرید شرکتی.

چه چیزی را در مورد الگوی فرمان به خاطر بسپارید

برای خلاصه کردن، موارد زیر را در مورد الگوی فرمان به خاطر بسپارید:

  • اصول جامد طراحی تک مسئولیتی و طراحی باز-بسته را اعمال می کند.
  • این رفتار دستورات را کپسوله می‌کند و از هم جدا می‌کند، که کد شما را توسعه‌پذیرتر می‌کند.
  • در JDK با کلاس Thread و رابط های Runnable و ActionListener استفاده می شود.
  • رفتار دستورات را در یک اجرای Command محصور می کند.
  • به شما امکان می دهد دستورات واحد را اجرا و برگردانید.
  • به شما امکان می دهد چندین فرمان را با هم اجرا و برگردانید.