Files

title, shortTitle, category, language, tag
title shortTitle category language tag
Balking Balking Concurrency ar
Decoupling

الغرض

يتم استخدام نمط Balking لمنع كائن من تنفيذ كود معين إذا كان في حالة غير مكتملة أو غير مناسبة.

الشرح

مثال من الحياة الواقعية

في غسالة الملابس هناك زر بدء لتشغيل غسل الملابس. عندما تكون الغسالة غير نشطة، يعمل الزر كما هو متوقع، ولكن إذا كانت الغسالة تغسل بالفعل، فإن الزر لا يفعل شيئًا.

بمعنى آخر

باستخدام نمط Balking، يتم تنفيذ كود معين فقط إذا كان الكائن في حالة معينة.

تقول ويكيبيديا

نمط Balking هو نمط تصميم برمجي ينفذ إجراء على كائن فقط عندما يكون الكائن في حالة معينة. على سبيل المثال، إذا كان الكائن يقرأ ملفات ZIP واستدعى أسلوب get على الكائن عندما لا يكون الملف ZIP مفتوحًا، فإن الكائن "يرفض" (balk) الطلب.

مثال برمجي

في هذا المثال من التنفيذ، WashingMachine هو كائن له حالتان يمكن أن يكونا: ENABLED و WASHING (مفعل و يغسل على التوالي). إذا كانت الغسالة في حالة ENABLED، فإن الحالة تتغير إلى WASHING باستخدام طريقة آمنة ضد الخيوط (thread-safe). من ناحية أخرى، إذا كانت الغسالة بالفعل تغسل وأي خيط آخر ينفذ wash()، فلن يتم تغيير الحالة وتنتهي تنفيذ الطريقة دون القيام بأي شيء.

إليك الأجزاء ذات الصلة من فئة WashingMachine.

@Slf4j
public class WashingMachine {

    private final DelayProvider delayProvider;
    private WashingMachineState washingMachineState;

    public WashingMachine(DelayProvider delayProvider) {
        this.delayProvider = delayProvider;
        this.washingMachineState = WashingMachineState.ENABLED;
    }

    public WashingMachineState getWashingMachineState() {
        return washingMachineState;
    }
    
    public void wash() {
        synchronized (this) {
            var machineState = getWashingMachineState();
            LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState);
            if (this.washingMachineState == WashingMachineState.WASHING) {
                LOGGER.error("Cannot wash if the machine has been already washing!");
                return;
            }
            this.washingMachineState = WashingMachineState.WASHING;
        }
        LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
        this.delayProvider.executeAfterDelay(50, TimeUnit.MILLISECONDS, this::endOfWashing);
    }
    
    public synchronized void endOfWashing() {
        washingMachineState = WashingMachineState.ENABLED;
        LOGGER.info("{}: Washing completed.", Thread.currentThread().getId());
    }
}

هنا الواجهة البسيطة DelayProvider المستخدمة من قبل WashingMachine.

public interface DelayProvider {
    void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task);
}

الآن نقدم التطبيق باستخدام WashingMachine.

public static void main(String... args) {
    final var washingMachine = new WashingMachine();
    var executorService = Executors.newFixedThreadPool(3);
    for (int i = 0; i < 3; i++) {
        executorService.execute(washingMachine::wash);
    }
    executorService.shutdown();
    try {
        executorService.awaitTermination(10, TimeUnit.SECONDS);    
    } catch (InterruptedException ie) {
        LOGGER.error("ERROR: Waiting on executor service shutdown!");
        Thread.currentThread().interrupt();
    }
}

إليك مخرجات التطبيق في وحدة التحكم.

14:02:52.268 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Actual machine state: ENABLED
14:02:52.272 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Doing the washing
14:02:52.272 [pool-1-thread-3] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-3: Actual machine state: WASHING
14:02:52.273 [pool-1-thread-3] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing!
14:02:52.273 [pool-1-thread-1] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-1: Actual machine state: WASHING
14:02:52.273 [pool-1-thread-1] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing!
14:02:52.324 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - 14: Washing completed.

مخطط الفئات

alt text

القابلية للتطبيق

استخدم نمط Balking عندما

  • يجب على كائن تنفيذ كود معين فقط عندما يكون في حالة معينة.
  • الكائنات في حالة معرضة للتوقف مؤقتًا، ولكن لفترة زمنية غير محددة.

الأنماط ذات الصلة

المراجع