---
title: "أسلوب القالب"
type: "design-pattern"
slug: "template-method"
url: "http://localhost:3000/ar/design-patterns/template-method.md"
category: "الأنماط السلوكية"
description: "أسلوب القالب هو نمط تصميم سلوكي يُعرّف الهيكل العام لخوارزمية في الصنف الأساسي، لكنه يتيح للأصناف الفرعية إعادة تعريف خطوات محددة من الخوارزمية دون تغيير بنيتها."
languages: ["java", "csharp", "cpp", "go", "php", "python", "ruby", "rust", "swift", "typescript"]
---
# أسلوب القالب

> أسلوب القالب هو نمط تصميم سلوكي يُعرّف الهيكل العام لخوارزمية في الصنف الأساسي، لكنه يتيح للأصناف الفرعية إعادة تعريف خطوات محددة من الخوارزمية دون تغيير بنيتها.

## Intent

**أسلوب القالب** هو نمط تصميم سلوكي يُعرّف الهيكل العام لخوارزمية في الصنف الأساسي، لكنه يتيح للأصناف الفرعية إعادة تعريف خطوات محددة من الخوارزمية دون تغيير بنيتها.

## Problem

تخيّل أنك تنشئ تطبيقًا للتنقيب عن البيانات (data mining) يحلّل مستندات الشركات. يُغذّي المستخدمون التطبيق بمستندات بصيغ مختلفة (PDF، DOC، CSV)، ويحاول استخراج بيانات ذات معنى من هذه المستندات بصيغة موحّدة.

كان بإمكان النسخة الأولى من التطبيق العمل مع ملفات DOC فقط. وفي النسخة التالية، أصبح قادرًا على دعم ملفات CSV. وبعد شهر، “علّمته” استخراج البيانات من ملفات PDF.

أصناف التنقيب عن البيانات احتوت على كثير من الشيفرة المكررة.

في مرحلة ما، لاحظت أن الأصناف الثلاثة جميعها تحتوي على كثير من الشيفرة المتشابهة. ففي حين كانت الشيفرة المعنية بالتعامل مع صيغ البيانات المختلفة مختلفة تمامًا في كل الأصناف، فإن الشيفرة الخاصة بمعالجة البيانات وتحليلها متطابقة تقريبًا. أليس من الرائع التخلص من تكرار الشيفرة مع إبقاء بنية الخوارزمية كما هي؟

كانت هناك مشكلة أخرى تتعلق بشيفرة العميل التي تستخدم هذه الأصناف. فقد احتوت على الكثير من الشروط التي تختار المسار المناسب للتنفيذ بحسب صنف كائن المعالجة. ولو كان للأصناف الثلاثة المعالِجة واجهة مشتركة أو صنف أساسي مشترك، لتمكنت من إزالة الشروط من شيفرة العميل واستخدام تعدد الأشكال (polymorphism) عند استدعاء الأساليب على كائن المعالجة.

## Solution

يقترح نمط أسلوب القالب أن تُقسّم الخوارزمية إلى سلسلة من الخطوات، وتحوّل هذه الخطوات إلى أساليب، وتضع سلسلة من الاستدعاءات لهذه الأساليب داخل _أسلوب قالب_ واحد. ويمكن أن تكون الخطوات إمّا `abstract` (مجردة)، أو أن تمتلك تطبيقًا افتراضيًا ما. ولاستخدام الخوارزمية، يُفترض أن يوفّر العميل صنفه الفرعي الخاص، ويُنفّذ جميع الخطوات المجردة، ويُعيد تعريف بعض الخطوات الاختيارية عند الحاجة (لكن ليس أسلوب القالب نفسه).

لنرَ كيف سيجري ذلك في تطبيق التنقيب عن البيانات لدينا. يمكننا إنشاء صنف أساسي لخوارزميات التحليل الثلاث جميعها. يُعرّف هذا الصنف أسلوب قالب يتكوّن من سلسلة من الاستدعاءات لمختلف خطوات معالجة المستندات.

يقسّم أسلوب القالب الخوارزمية إلى خطوات، مما يتيح للأصناف الفرعية إعادة تعريف هذه الخطوات لكن ليس الأسلوب الفعلي.

في البداية، يمكننا إعلان جميع الخطوات على أنها `abstract` (مجردة)، مما يُجبر الأصناف الفرعية على توفير تطبيقاتها الخاصة لهذه الأساليب. وفي حالتنا، تمتلك الأصناف الفرعية بالفعل جميع التطبيقات اللازمة، لذا فإن الشيء الوحيد الذي قد نحتاج إلى فعله هو تعديل تواقيع الأساليب لتطابق أساليب الصنف الأساسي.

الآن، لنرَ ما يمكننا فعله للتخلص من الشيفرة المكررة. يبدو أن الشيفرة الخاصة بفتح/إغلاق الملفات واستخراج/تحليل البيانات تختلف باختلاف صيغ البيانات، لذا لا فائدة من المساس بتلك الأساليب. ومع ذلك، فإن تطبيق خطوات أخرى، مثل تحليل البيانات الخام وتأليف التقارير، متشابه جدًا، لذا يمكن رفعه إلى الصنف الأساسي حيث يمكن للأصناف الفرعية مشاركة تلك الشيفرة.

كما ترى، لدينا نوعان من الخطوات:

* _الخطوات المجردة_ يجب أن يُنفّذها كل صنف فرعي
* _الخطوات الاختيارية_ تمتلك بالفعل تطبيقًا افتراضيًا ما، لكن لا يزال بالإمكان إعادة تعريفها عند الحاجة

هناك نوع آخر من الخطوات يُسمى _الخطافات_ (hooks). الخطّاف هو خطوة اختيارية بجسم فارغ. وسيعمل أسلوب القالب حتى لو لم تُعَد تعريف الخطّاف. وعادةً ما تُوضع الخطافات قبل الخطوات الحاسمة للخوارزميات وبعدها، مما يوفّر للأصناف الفرعية نقاط توسيع إضافية للخوارزمية.

## Structure

1. يُعلن **الصنف المجرد** عن أساليب تعمل كخطوات لخوارزمية، إضافةً إلى أسلوب القالب الفعلي الذي يستدعي هذه الأساليب بترتيب محدد. ويمكن أن تكون الخطوات إمّا مُعلَنة على أنها `abstract` (مجردة) أو أن تمتلك تطبيقًا افتراضيًا ما.
2. تستطيع **الأصناف المحسوسة** إعادة تعريف جميع الخطوات، لكن ليس أسلوب القالب نفسه.

## Pseudocode

في هذا المثال، يوفّر نمط **أسلوب القالب** “هيكلًا عامًا” لمختلف فروع الذكاء الاصطناعي في لعبة فيديو استراتيجية بسيطة.

أصناف الذكاء الاصطناعي للعبة فيديو بسيطة.

تمتلك جميع الأعراق في اللعبة تقريبًا الأنواع نفسها من الوحدات والمباني. لذلك يمكنك إعادة استخدام بنية الذكاء الاصطناعي نفسها لمختلف الأعراق، مع القدرة على إعادة تعريف بعض التفاصيل. وبهذا الأسلوب، يمكنك إعادة تعريف ذكاء الأوركيين (orcs) ليكون أكثر عدوانية، وجعل البشر أكثر ميلًا للدفاع، وجعل الوحوش غير قادرة على بناء أي شيء. وإضافة عرق جديد إلى اللعبة ستتطلب إنشاء صنف فرعي جديد للذكاء الاصطناعي وإعادة تعريف الأساليب الافتراضية المُعلَنة في صنف الذكاء الاصطناعي الأساسي.

// يُعرّف الصنف المجرد أسلوب قالب يحتوي على هيكل عام لخوارزمية
// ما، مكوَّن من استدعاءات، عادةً لعمليات أولية مجردة. تُنفّذ
// الأصناف الفرعية المحسوسة هذه العمليات، لكنها تترك أسلوب
// القالب نفسه كما هو دون
// تغيير.
class GameAI is
    // يُعرّف أسلوب القالب الهيكل العام للخوارزمية.
    method turn() is
        collectResources()
        buildStructures()
        buildUnits()
        attack()

    // يمكن تطبيق بعض الخطوات مباشرةً في الصنف
    // الأساسي.
    method collectResources() is
        foreach (s in this.builtStructures) do
            s.collect()

    // وبعضها يمكن تعريفه على أنه مجرد.
    abstract method buildStructures()
    abstract method buildUnits()

    // يمكن أن يحتوي الصنف على عدة أساليب قالب.
    method attack() is
        enemy = closestEnemy()
        if (enemy == null)
            sendScouts(map.center)
        else
            sendWarriors(enemy.position)

    abstract method sendScouts(position)
    abstract method sendWarriors(position)

// يجب على الأصناف المحسوسة تنفيذ جميع العمليات المجردة
// للصنف الأساسي، لكن يجب ألا تُعيد تعريف أسلوب القالب
// نفسه.
class OrcsAI extends GameAI is
    method buildStructures() is
        if (there are some resources) then
            // ابنِ المزارع، ثم الثكنات، ثم الحصن.

    method buildUnits() is
        if (there are plenty of resources) then
            if (there are no scouts)
                // ابنِ عاملًا (peon) وأضفه إلى مجموعة الكشافة.
            else
                // ابنِ مقاتلًا (grunt) وأضفه إلى مجموعة المحاربين.

    // ...

    method sendScouts(position) is
        if (scouts.length > 0) then
            // أرسل الكشافة إلى الموقع.

    method sendWarriors(position) is
        if (warriors.length > 5) then
            // أرسل المحاربين إلى الموقع.

// يمكن للأصناف الفرعية أيضًا إعادة تعريف بعض العمليات
// بتطبيق افتراضي.
class MonstersAI extends GameAI is
    method collectResources() is
        // الوحوش لا تجمع الموارد.

    method buildStructures() is
        // الوحوش لا تبني مبانٍ.

    method buildUnits() is
        // الوحوش لا تبني وحدات.

## Applicability

استخدم نمط أسلوب القالب عندما تريد أن تتيح للعملاء توسيع خطوات معينة فقط من خوارزمية، دون توسيع الخوارزمية بأكملها أو بنيتها.

 يتيح لك أسلوب القالب تحويل خوارزمية متراصة (monolithic) إلى سلسلة من الخطوات المنفردة التي يمكن للأصناف الفرعية توسيعها بسهولة مع الحفاظ على البنية المُعرّفة في الصنف الأساسي.

 استخدم النمط عندما يكون لديك عدة أصناف تحتوي على خوارزميات شبه متطابقة مع بعض الاختلافات الطفيفة. ونتيجةً لذلك، قد تضطر إلى تعديل جميع الأصناف عند تغيّر الخوارزمية.

 عندما تحوّل مثل هذه الخوارزمية إلى أسلوب قالب، يمكنك أيضًا رفع الخطوات ذات التطبيقات المتشابهة إلى الصنف الأساسي، مما يلغي تكرار الشيفرة. أما الشيفرة التي تختلف بين الأصناف الفرعية فيمكن أن تبقى في الأصناف الفرعية.

## How to Implement

1. حلّل الخوارزمية المستهدفة لمعرفة ما إذا كان بإمكانك تقسيمها إلى خطوات. فكّر في الخطوات المشتركة بين جميع الأصناف الفرعية وتلك التي ستكون فريدة دائمًا.
2. أنشئ الصنف الأساسي المجرد وأعلن عن أسلوب القالب ومجموعة من الأساليب المجردة التي تمثّل خطوات الخوارزمية. ارسم مخطط بنية الخوارزمية داخل أسلوب القالب عبر استدعاء الخطوات المقابلة. فكّر في جعل أسلوب القالب `final` لمنع الأصناف الفرعية من إعادة تعريفه.
3. لا بأس إن انتهى الأمر بأن تكون جميع الخطوات مجردة. ومع ذلك، قد تستفيد بعض الخطوات من امتلاك تطبيق افتراضي. فالأصناف الفرعية ليست مضطرة لتنفيذ تلك الأساليب.
4. فكّر في إضافة خطافات (hooks) بين الخطوات الحاسمة للخوارزمية.
5. لكل صيغة مختلفة من الخوارزمية، أنشئ صنفًا فرعيًا محسوسًا جديدًا. فهو _يجب_ أن يُنفّذ جميع الخطوات المجردة، لكنه _قد_ يُعيد أيضًا تعريف بعض الخطوات الاختيارية.

## Pros

* يمكنك السماح للعملاء بإعادة تعريف أجزاء معينة فقط من خوارزمية كبيرة، مما يجعلهم أقل تأثرًا بالتغييرات التي تطرأ على أجزاء أخرى من الخوارزمية.
* يمكنك رفع الشيفرة المكررة إلى صنف أساسي.

## Cons

* قد يكون بعض العملاء مُقيَّدين بالهيكل العام المُتاح للخوارزمية.
* قد تنتهك _مبدأ ليسكوف للاستبدال_ عبر كبت التطبيق الافتراضي لإحدى الخطوات من خلال صنف فرعي.
* تميل أساليب القالب إلى أن تصبح أصعب في الصيانة كلما زاد عدد خطواتها.

## Relations with Other Patterns

* [أسلوب المصنع](/ar/design-patterns/factory-method) هو تخصيص لـ[أسلوب القالب](/ar/design-patterns/template-method). وفي الوقت نفسه، قد يكون _أسلوب المصنع_ بمثابة خطوة ضمن _أسلوب قالب_ كبير.
* [أسلوب القالب](/ar/design-patterns/template-method) يعتمد على الوراثة: فهو يتيح لك تغيير أجزاء من خوارزمية عبر توسيع تلك الأجزاء في الأصناف الفرعية. أما [الاستراتيجية](/ar/design-patterns/strategy) فتعتمد على التركيب: إذ يمكنك تغيير أجزاء من سلوك الكائن عبر تزويده باستراتيجيات مختلفة تقابل ذلك السلوك. يعمل _أسلوب القالب_ على مستوى الصنف، لذا فهو ساكن (static). أما _الاستراتيجية_ فتعمل على مستوى الكائن، مما يتيح لك تبديل السلوكيات أثناء التشغيل.
## Relations

**Related patterns**

- [طريقة المصنع](/ar/design-patterns/factory-method.md)
- [الاستراتيجية](/ar/design-patterns/strategy.md)

## Code Examples

### java

```java
package refactoring_guru.template_method.example.networks;

/**
 * الصنف الأساسي للشبكة الاجتماعية.
 */
public abstract class Network {
    String userName;
    String password;

    Network() {}

    /**
     * نشر البيانات إلى أي شبكة كانت.
     */
    public boolean post(String message) {
        // المصادقة قبل النشر. كل شبكة تستخدم طريقة
        // مصادقة مختلفة.
        if (logIn(this.userName, this.password)) {
            // إرسال بيانات المنشور.
            boolean result =  sendData(message.getBytes());
            logOut();
            return result;
        }
        return false;
    }

    abstract boolean logIn(String userName, String password);
    abstract boolean sendData(byte[] data);
    abstract void logOut();
}

package refactoring_guru.template_method.example.networks;

/**
 * صنف لشبكة اجتماعية
 */
public class Facebook extends Network {
    public Facebook(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }

    public boolean logIn(String userName, String password) {
        System.out.println("\nChecking user's parameters");
        System.out.println("Name: " + this.userName);
        System.out.print("Password: ");
        for (int i = 0; i < this.password.length(); i++) {
            System.out.print("*");
        }
        simulateNetworkLatency();
        System.out.println("\n\nLogIn success on Facebook");
        return true;
    }

    public boolean sendData(byte[] data) {
        boolean messagePosted = true;
        if (messagePosted) {
            System.out.println("Message: '" + new String(data) + "' was posted on Facebook");
            return true;
        } else {
            return false;
        }
    }

    public void logOut() {
        System.out.println("User: '" + userName + "' was logged out from Facebook");
    }

    private void simulateNetworkLatency() {
        try {
            int i = 0;
            System.out.println();
            while (i < 10) {
                System.out.print(".");
                Thread.sleep(500);
                i++;
            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

package refactoring_guru.template_method.example.networks;

/**
 * صنف لشبكة اجتماعية
 */
public class Twitter extends Network {

    public Twitter(String userName, String password) {
        this.userName = userName;
        this.password = password;
    }

    public boolean logIn(String userName, String password) {
        System.out.println("\nChecking user's parameters");
        System.out.println("Name: " + this.userName);
        System.out.print("Password: ");
        for (int i = 0; i < this.password.length(); i++) {
            System.out.print("*");
        }
        simulateNetworkLatency();
        System.out.println("\n\nLogIn success on Twitter");
        return true;
    }

    public boolean sendData(byte[] data) {
        boolean messagePosted = true;
        if (messagePosted) {
            System.out.println("Message: '" + new String(data) + "' was posted on Twitter");
            return true;
        } else {
            return false;
        }
    }

    public void logOut() {
        System.out.println("User: '" + userName + "' was logged out from Twitter");
    }

    private void simulateNetworkLatency() {
        try {
            int i = 0;
            System.out.println();
            while (i < 10) {
                System.out.print(".");
                Thread.sleep(500);
                i++;
            }
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

package refactoring_guru.template_method.example;

import refactoring_guru.template_method.example.networks.Facebook;
import refactoring_guru.template_method.example.networks.Network;
import refactoring_guru.template_method.example.networks.Twitter;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * صنف العرض التوضيحي. كل شيء يجتمع هنا.
 */
public class Demo {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        Network network = null;
        System.out.print("Input user name: ");
        String userName = reader.readLine();
        System.out.print("Input password: ");
        String password = reader.readLine();

        // إدخال الرسالة.
        System.out.print("Input message: ");
        String message = reader.readLine();

        System.out.println("\nChoose social network for posting message.\n" +
                "1 - Facebook\n" +
                "2 - Twitter");
        int choice = Integer.parseInt(reader.readLine());

        // إنشاء كائن الشبكة المناسب وإرسال الرسالة.
        if (choice == 1) {
            network = new Facebook(userName, password);
        } else if (choice == 2) {
            network = new Twitter(userName, password);
        }
        network.post(message);
    }
}

Input user name: Jhonatan
Input password: qswe
Input message: Hello, World!

Choose social network for posting message.
1 - Facebook
2 - Twitter
2

Checking user's parameters
Name: Jhonatan
Password: ****
..........

LogIn success on Twitter
Message: 'Hello, World!' was posted on Twitter
User: 'Jhonatan' was logged out from Twitter
```

### csharp

```csharp
using System;

namespace RefactoringGuru.DesignPatterns.TemplateMethod.Conceptual
{
    // يُعرّف الصنف المجرد أسلوب قالب يحتوي على هيكل عام
    // لخوارزمية ما، يتألف من استدعاءات لعمليات أولية مجردة
    // (عادةً).
    //
    // على الأصناف الفرعية المحسوسة تنفيذ هذه العمليات، مع
    // ترك أسلوب القالب نفسه دون تغيير.
    abstract class AbstractClass
    {
        // يُعرّف أسلوب القالب الهيكل العام للخوارزمية.
        public void TemplateMethod()
        {
            this.BaseOperation1();
            this.RequiredOperations1();
            this.BaseOperation2();
            this.Hook1();
            this.RequiredOperation2();
            this.BaseOperation3();
            this.Hook2();
        }

        // هذه العمليات تمتلك تطبيقات بالفعل.
        protected void BaseOperation1()
        {
            Console.WriteLine("AbstractClass says: I am doing the bulk of the work");
        }

        protected void BaseOperation2()
        {
            Console.WriteLine("AbstractClass says: But I let subclasses override some operations");
        }

        protected void BaseOperation3()
        {
            Console.WriteLine("AbstractClass says: But I am doing the bulk of the work anyway");
        }
        
        // يجب تنفيذ هذه العمليات في الأصناف الفرعية.
        protected abstract void RequiredOperations1();

        protected abstract void RequiredOperation2();
        
        // هذه "خطافات". قد تُعيد الأصناف الفرعية تعريفها، لكن
        // ذلك ليس إلزاميًا لأن الخطافات تمتلك بالفعل تطبيقًا
        // افتراضيًا (لكنه فارغ). توفّر الخطافات نقاط توسيع
        // إضافية في بعض المواضع الحاسمة من الخوارزمية.
        protected virtual void Hook1() { }

        protected virtual void Hook2() { }
    }

    // يجب على الأصناف المحسوسة تنفيذ جميع العمليات المجردة
    // للصنف الأساسي. ويمكنها أيضًا إعادة تعريف بعض العمليات
    // بتطبيق افتراضي.
    class ConcreteClass1 : AbstractClass
    {
        protected override void RequiredOperations1()
        {
            Console.WriteLine("ConcreteClass1 says: Implemented Operation1");
        }

        protected override void RequiredOperation2()
        {
            Console.WriteLine("ConcreteClass1 says: Implemented Operation2");
        }
    }

    // عادةً ما تُعيد الأصناف المحسوسة تعريف جزء يسير فقط من
    // عمليات الصنف الأساسي.
    class ConcreteClass2 : AbstractClass
    {
        protected override void RequiredOperations1()
        {
            Console.WriteLine("ConcreteClass2 says: Implemented Operation1");
        }

        protected override void RequiredOperation2()
        {
            Console.WriteLine("ConcreteClass2 says: Implemented Operation2");
        }

        protected override void Hook1()
        {
            Console.WriteLine("ConcreteClass2 says: Overridden Hook1");
        }
    }

    class Client
    {
        // تستدعي شيفرة العميل أسلوب القالب لتنفيذ الخوارزمية.
        // ولا يتعيّن على شيفرة العميل معرفة الصنف المحسوس
        // للكائن الذي تتعامل معه، طالما أنها تتعامل مع الكائنات
        // عبر واجهة صنفها الأساسي.
        public static void ClientCode(AbstractClass abstractClass)
        {
            // ...
            abstractClass.TemplateMethod();
            // ...
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Same client code can work with different subclasses:");

            Client.ClientCode(new ConcreteClass1());

            Console.Write("\n");
            
            Console.WriteLine("Same client code can work with different subclasses:");
            Client.ClientCode(new ConcreteClass2());
        }
    }
}

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway
```

### cpp

```cpp
/**
 * يُعرّف الصنف المجرد أسلوب قالب يحتوي على هيكل عام لخوارزمية ما،
 * يتألف من استدعاءات لعمليات أولية مجردة (عادةً).
 *
 * على الأصناف الفرعية المحسوسة تنفيذ هذه العمليات، مع ترك أسلوب
 * القالب نفسه دون تغيير.
 */
class AbstractClass {
  /**
   * يُعرّف أسلوب القالب الهيكل العام للخوارزمية.
   */
 public:
  void TemplateMethod() const {
    this->BaseOperation1();
    this->RequiredOperations1();
    this->BaseOperation2();
    this->Hook1();
    this->RequiredOperation2();
    this->BaseOperation3();
    this->Hook2();
  }
  /**
   * هذه العمليات تمتلك تطبيقات بالفعل.
   */
 protected:
  void BaseOperation1() const {
    std::cout << "AbstractClass says: I am doing the bulk of the work\n";
  }
  void BaseOperation2() const {
    std::cout << "AbstractClass says: But I let subclasses override some operations\n";
  }
  void BaseOperation3() const {
    std::cout << "AbstractClass says: But I am doing the bulk of the work anyway\n";
  }
  /**
   * يجب تنفيذ هذه العمليات في الأصناف الفرعية.
   */
  virtual void RequiredOperations1() const = 0;
  virtual void RequiredOperation2() const = 0;
  /**
   * هذه "خطافات". قد تُعيد الأصناف الفرعية تعريفها، لكن ذلك ليس
   * إلزاميًا لأن الخطافات تمتلك بالفعل تطبيقًا افتراضيًا (لكنه فارغ).
   * توفّر الخطافات نقاط توسيع إضافية في بعض المواضع الحاسمة من
   * الخوارزمية.
   */
  virtual void Hook1() const {}
  virtual void Hook2() const {}
};
/**
 * يجب على الأصناف المحسوسة تنفيذ جميع العمليات المجردة للصنف الأساسي.
 * ويمكنها أيضًا إعادة تعريف بعض العمليات بتطبيق افتراضي.
 */
class ConcreteClass1 : public AbstractClass {
 protected:
  void RequiredOperations1() const override {
    std::cout << "ConcreteClass1 says: Implemented Operation1\n";
  }
  void RequiredOperation2() const override {
    std::cout << "ConcreteClass1 says: Implemented Operation2\n";
  }
};
/**
 * عادةً ما تُعيد الأصناف المحسوسة تعريف جزء يسير فقط من عمليات الصنف الأساسي.
 */
class ConcreteClass2 : public AbstractClass {
 protected:
  void RequiredOperations1() const override {
    std::cout << "ConcreteClass2 says: Implemented Operation1\n";
  }
  void RequiredOperation2() const override {
    std::cout << "ConcreteClass2 says: Implemented Operation2\n";
  }
  void Hook1() const override {
    std::cout << "ConcreteClass2 says: Overridden Hook1\n";
  }
};
/**
 * تستدعي شيفرة العميل أسلوب القالب لتنفيذ الخوارزمية. ولا يتعيّن
 * على شيفرة العميل معرفة الصنف المحسوس للكائن الذي تتعامل معه،
 * طالما أنها تتعامل مع الكائنات عبر واجهة صنفها الأساسي.
 */
void ClientCode(AbstractClass *class_) {
  // ...
  class_->TemplateMethod();
  // ...
}

int main() {
  std::cout << "Same client code can work with different subclasses:\n";
  ConcreteClass1 *concreteClass1 = new ConcreteClass1;
  ClientCode(concreteClass1);
  std::cout << "\n";
  std::cout << "Same client code can work with different subclasses:\n";
  ConcreteClass2 *concreteClass2 = new ConcreteClass2;
  ClientCode(concreteClass2);
  delete concreteClass1;
  delete concreteClass2;
  return 0;
}

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway
```

### go

```go
package main

type IOtp interface {
	genRandomOTP(int) string
	saveOTPCache(string)
	getMessage(string) string
	sendNotification(string) error
}

// type otp struct {
// }

// func (o *otp) genAndSendOTP(iOtp iOtp, otpLength int) error {
// 	otp := iOtp.genRandomOTP(otpLength)
// 	iOtp.saveOTPCache(otp)
// 	message := iOtp.getMessage(otp)
// 	err := iOtp.sendNotification(message)
// 	if err != nil {
// 		return err
// 	}
// 	return nil
// }

type Otp struct {
	iOtp IOtp
}

func (o *Otp) genAndSendOTP(otpLength int) error {
	otp := o.iOtp.genRandomOTP(otpLength)
	o.iOtp.saveOTPCache(otp)
	message := o.iOtp.getMessage(otp)
	err := o.iOtp.sendNotification(message)
	if err != nil {
		return err
	}
	return nil
}

package main

import "fmt"

type Sms struct {
	Otp
}

func (s *Sms) genRandomOTP(len int) string {
	randomOTP := "1234"
	fmt.Printf("SMS: generating random otp %s\n", randomOTP)
	return randomOTP
}

func (s *Sms) saveOTPCache(otp string) {
	fmt.Printf("SMS: saving otp: %s to cache\n", otp)
}

func (s *Sms) getMessage(otp string) string {
	return "SMS OTP for login is " + otp
}

func (s *Sms) sendNotification(message string) error {
	fmt.Printf("SMS: sending sms: %s\n", message)
	return nil
}

package main

import "fmt"

type Email struct {
	Otp
}

func (s *Email) genRandomOTP(len int) string {
	randomOTP := "1234"
	fmt.Printf("EMAIL: generating random otp %s\n", randomOTP)
	return randomOTP
}

func (s *Email) saveOTPCache(otp string) {
	fmt.Printf("EMAIL: saving otp: %s to cache\n", otp)
}

func (s *Email) getMessage(otp string) string {
	return "EMAIL OTP for login is " + otp
}

func (s *Email) sendNotification(message string) error {
	fmt.Printf("EMAIL: sending email: %s\n", message)
	return nil
}

package main

import "fmt"

func main() {
	// otp := otp{}

	// smsOTP := &sms{
	// 	otp: otp,
	// }

	// smsOTP.genAndSendOTP(smsOTP, 4)

	// emailOTP := &email{
	// 	otp: otp,
	// }
	// emailOTP.genAndSendOTP(emailOTP, 4)
	// fmt.Scanln()
	smsOTP := &Sms{}
	o := Otp{
		iOtp: smsOTP,
	}
	o.genAndSendOTP(4)

	fmt.Println("")
	emailOTP := &Email{}
	o = Otp{
		iOtp: emailOTP,
	}
	o.genAndSendOTP(4)

}

SMS: generating random otp 1234
SMS: saving otp: 1234 to cache
SMS: sending sms: SMS OTP for login is 1234

EMAIL: generating random otp 1234
EMAIL: saving otp: 1234 to cache
EMAIL: sending email: EMAIL OTP for login is 1234
```

### php

```php
<?php

namespace RefactoringGuru\TemplateMethod\Conceptual;

/**
 * يُعرّف الصنف المجرد أسلوب قالب يحتوي على هيكل عام لخوارزمية ما،
 * يتألف من استدعاءات لعمليات أولية مجردة (عادةً).
 *
 * على الأصناف الفرعية المحسوسة تنفيذ هذه العمليات، مع ترك أسلوب
 * القالب نفسه دون تغيير.
 */
abstract class AbstractClass
{
    /**
     * يُعرّف أسلوب القالب الهيكل العام للخوارزمية.
     */
    final public function templateMethod(): void
    {
        $this->baseOperation1();
        $this->requiredOperations1();
        $this->baseOperation2();
        $this->hook1();
        $this->requiredOperation2();
        $this->baseOperation3();
        $this->hook2();
    }

    /**
     * هذه العمليات تمتلك تطبيقات بالفعل.
     */
    protected function baseOperation1(): void
    {
        echo "AbstractClass says: I am doing the bulk of the work\n";
    }

    protected function baseOperation2(): void
    {
        echo "AbstractClass says: But I let subclasses override some operations\n";
    }

    protected function baseOperation3(): void
    {
        echo "AbstractClass says: But I am doing the bulk of the work anyway\n";
    }

    /**
     * يجب تنفيذ هذه العمليات في الأصناف الفرعية.
     */
    abstract protected function requiredOperations1(): void;

    abstract protected function requiredOperation2(): void;

    /**
     * هذه "خطافات". قد تُعيد الأصناف الفرعية تعريفها، لكن ذلك ليس
     * إلزاميًا لأن الخطافات تمتلك بالفعل تطبيقًا افتراضيًا (لكنه فارغ).
     * توفّر الخطافات نقاط توسيع إضافية في بعض المواضع الحاسمة من
     * الخوارزمية.
     */
    protected function hook1(): void
    {
    }

    protected function hook2(): void
    {
    }
}

/**
 * يجب على الأصناف المحسوسة تنفيذ جميع العمليات المجردة للصنف الأساسي.
 * ويمكنها أيضًا إعادة تعريف بعض العمليات بتطبيق افتراضي.
 */
class ConcreteClass1 extends AbstractClass
{
    protected function requiredOperations1(): void
    {
        echo "ConcreteClass1 says: Implemented Operation1\n";
    }

    protected function requiredOperation2(): void
    {
        echo "ConcreteClass1 says: Implemented Operation2\n";
    }
}

/**
 * عادةً ما تُعيد الأصناف المحسوسة تعريف جزء يسير فقط من عمليات الصنف الأساسي.
 */
class ConcreteClass2 extends AbstractClass
{
    protected function requiredOperations1(): void
    {
        echo "ConcreteClass2 says: Implemented Operation1\n";
    }

    protected function requiredOperation2(): void
    {
        echo "ConcreteClass2 says: Implemented Operation2\n";
    }

    protected function hook1(): void
    {
        echo "ConcreteClass2 says: Overridden Hook1\n";
    }
}

/**
 * تستدعي شيفرة العميل أسلوب القالب لتنفيذ الخوارزمية. ولا يتعيّن
 * على شيفرة العميل معرفة الصنف المحسوس للكائن الذي تتعامل معه،
 * طالما أنها تتعامل مع الكائنات عبر واجهة صنفها الأساسي.
 */
function clientCode(AbstractClass $class)
{
    // ...
    $class->templateMethod();
    // ...
}

echo "Same client code can work with different subclasses:\n";
clientCode(new ConcreteClass1());
echo "\n";

echo "Same client code can work with different subclasses:\n";
clientCode(new ConcreteClass2());

Same client code can work with different subclasses:
AbstractClass says: I am doing bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses to override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing bulk of the work anyway

Same client code can work with different subclasses:
AbstractClass says: I am doing bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses to override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing bulk of the work anyway

<?php

namespace RefactoringGuru\TemplateMethod\RealWorld;

/**
 * يُعرّف الصنف المجرد أسلوب القالب ويعلن عن جميع خطواته.
 */
abstract class SocialNetwork
{
    protected $username;

    protected $password;

    public function __construct(string $username, string $password)
    {
        $this->username = $username;
        $this->password = $password;
    }

    /**
     * يستدعي أسلوب القالب الفعلي الخطوات المجردة بترتيب محدد. وقد
     * يُنفّذ الصنف الفرعي جميع الخطوات، مما يتيح لهذا الأسلوب نشر شيء
     * ما فعليًا على شبكة اجتماعية.
     */
    public function post(string $message): bool
    {
        // Authenticate before posting. Every network uses a different
        // authentication method.
        if ($this->logIn($this->username, $this->password)) {
            // إرسال بيانات المنشور. لكل الشبكات واجهات برمجية مختلفة.
            $result = $this->sendData($message);
            // ...
            $this->logOut();

            return $result;
        }

        return false;
    }

    /**
     * تُعلَن الخطوات على أنها مجردة لإجبار الأصناف الفرعية على تنفيذها
     * جميعًا.
     */
    abstract public function logIn(string $userName, string $password): bool;

    abstract public function sendData(string $message): bool;

    abstract public function logOut(): void;
}

/**
 * هذا الصنف المحسوس يُطبّق واجهة Facebook البرمجية (حسنًا، إنه يتظاهر بذلك).
 */
class Facebook extends SocialNetwork
{
    public function logIn(string $userName, string $password): bool
    {
        echo "\nChecking user's credentials...\n";
        echo "Name: " . $this->username . "\n";
        echo "Password: " . str_repeat("*", strlen($this->password)) . "\n";

        simulateNetworkLatency();

        echo "\n\nFacebook: '" . $this->username . "' has logged in successfully.\n";

        return true;
    }

    public function sendData(string $message): bool
    {
        echo "Facebook: '" . $this->username . "' has posted '" . $message . "'.\n";

        return true;
    }

    public function logOut(): void
    {
        echo "Facebook: '" . $this->username . "' has been logged out.\n";
    }
}

/**
 * هذا الصنف المحسوس يُطبّق واجهة Twitter البرمجية.
 */
class Twitter extends SocialNetwork
{
    public function logIn(string $userName, string $password): bool
    {
        echo "\nChecking user's credentials...\n";
        echo "Name: " . $this->username . "\n";
        echo "Password: " . str_repeat("*", strlen($this->password)) . "\n";

        simulateNetworkLatency();

        echo "\n\nTwitter: '" . $this->username . "' has logged in successfully.\n";

        return true;
    }

    public function sendData(string $message): bool
    {
        echo "Twitter: '" . $this->username . "' has posted '" . $message . "'.\n";

        return true;
    }

    public function logOut(): void
    {
        echo "Twitter: '" . $this->username . "' has been logged out.\n";
    }
}

/**
 * دالة مساعدة صغيرة تجعل أوقات الانتظار تبدو حقيقية.
 */
function simulateNetworkLatency()
{
    $i = 0;
    while ($i < 5) {
        echo ".";
        sleep(1);
        $i++;
    }
}

/**
 * شيفرة العميل.
 */
echo "Username: \n";
$username = readline();
echo "Password: \n";
$password = readline();
echo "Message: \n";
$message = readline();

echo "\nChoose the social network to post the message:\n" .
    "1 - Facebook\n" .
    "2 - Twitter\n";
$choice = readline();

// الآن، لننشئ كائن شبكة اجتماعية مناسبًا ونرسل الرسالة.
if ($choice == 1) {
    $network = new Facebook($username, $password);
} elseif ($choice == 2) {
    $network = new Twitter($username, $password);
} else {
    die("Sorry, I'm not sure what you mean by that.\n");
}
$network->post($message);

Username:
> neo
Password:
> 123123
Message:
> What is the Matrix?

Choose the social network to post the message:
1 - Facebook
2 - Twitter
> 1

Checking user's credentials...
Name: neo
Password: ******
.....

Facebook: 'neo' has logged in successfully.
Facebook: 'neo' has posted 'What is the Matrix?'.
Facebook: 'neo' has been logged out.
```

### python

```python
from abc import ABC, abstractmethod


class AbstractClass(ABC):
    """
    يُعرّف الصنف المجرد أسلوب قالب يحتوي على هيكل عام لخوارزمية ما،
    يتألف من استدعاءات لعمليات أولية مجردة (عادةً).

    على الأصناف الفرعية المحسوسة تنفيذ هذه العمليات، مع ترك أسلوب
    القالب نفسه دون تغيير.
    """

    def template_method(self) -> None:
        """
        يُعرّف أسلوب القالب الهيكل العام للخوارزمية.
        """

        self.base_operation1()
        self.required_operations1()
        self.base_operation2()
        self.hook1()
        self.required_operations2()
        self.base_operation3()
        self.hook2()

    # هذه العمليات تمتلك تطبيقات بالفعل.

    def base_operation1(self) -> None:
        print("AbstractClass says: I am doing the bulk of the work")

    def base_operation2(self) -> None:
        print("AbstractClass says: But I let subclasses override some operations")

    def base_operation3(self) -> None:
        print("AbstractClass says: But I am doing the bulk of the work anyway")

    # يجب تنفيذ هذه العمليات في الأصناف الفرعية.

    @abstractmethod
    def required_operations1(self) -> None:
        pass

    @abstractmethod
    def required_operations2(self) -> None:
        pass

    # هذه "خطافات". قد تُعيد الأصناف الفرعية تعريفها، لكن ذلك ليس
    # إلزاميًا لأن الخطافات تمتلك بالفعل تطبيقًا افتراضيًا (لكنه فارغ).
    # توفّر الخطافات نقاط توسيع إضافية في بعض المواضع الحاسمة من
    # الخوارزمية.

    def hook1(self) -> None:
        pass

    def hook2(self) -> None:
        pass


class ConcreteClass1(AbstractClass):
    """
    يجب على الأصناف المحسوسة تنفيذ جميع العمليات المجردة للصنف
    الأساسي. ويمكنها أيضًا إعادة تعريف بعض العمليات بتطبيق افتراضي.
    """

    def required_operations1(self) -> None:
        print("ConcreteClass1 says: Implemented Operation1")

    def required_operations2(self) -> None:
        print("ConcreteClass1 says: Implemented Operation2")


class ConcreteClass2(AbstractClass):
    """
    عادةً ما تُعيد الأصناف المحسوسة تعريف جزء يسير فقط من عمليات
    الصنف الأساسي.
    """

    def required_operations1(self) -> None:
        print("ConcreteClass2 says: Implemented Operation1")

    def required_operations2(self) -> None:
        print("ConcreteClass2 says: Implemented Operation2")

    def hook1(self) -> None:
        print("ConcreteClass2 says: Overridden Hook1")


def client_code(abstract_class: AbstractClass) -> None:
    """
    تستدعي شيفرة العميل أسلوب القالب لتنفيذ الخوارزمية. ولا يتعيّن
    على شيفرة العميل معرفة الصنف المحسوس للكائن الذي تتعامل معه،
    طالما أنها تتعامل مع الكائنات عبر واجهة صنفها الأساسي.
    """

    # ...
    abstract_class.template_method()
    # ...


if __name__ == "__main__":
    print("Same client code can work with different subclasses:")
    client_code(ConcreteClass1())
    print("")

    print("Same client code can work with different subclasses:")
    client_code(ConcreteClass2())

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway
```

### ruby

```ruby
# يُعرّف الصنف المجرد أسلوب قالب يحتوي على هيكل عام لخوارزمية ما،
# يتألف من استدعاءات لعمليات أولية مجردة (عادةً).
#
# على الأصناف الفرعية المحسوسة تنفيذ هذه العمليات، مع ترك أسلوب
# القالب نفسه دون تغيير.
class AbstractClass
  # يُعرّف أسلوب القالب الهيكل العام للخوارزمية.
  def template_method
    base_operation1
    required_operations1
    base_operation2
    hook1
    required_operations2
    base_operation3
    hook2
  end

  # هذه العمليات تمتلك تطبيقات بالفعل.

  def base_operation1
    puts 'AbstractClass says: I am doing the bulk of the work'
  end

  def base_operation2
    puts 'AbstractClass says: But I let subclasses override some operations'
  end

  def base_operation3
    puts 'AbstractClass says: But I am doing the bulk of the work anyway'
  end

  # يجب تنفيذ هذه العمليات في الأصناف الفرعية.
  def required_operations1
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  # @abstract
  def required_operations2
    raise NotImplementedError, "#{self.class} has not implemented method '#{__method__}'"
  end

  # هذه "خطافات". قد تُعيد الأصناف الفرعية تعريفها، لكن ذلك ليس
  # إلزاميًا لأن الخطافات تمتلك بالفعل تطبيقًا افتراضيًا (لكنه فارغ). توفّر
  # الخطافات نقاط توسيع إضافية في بعض المواضع الحاسمة من الخوارزمية.

  def hook1; end

  def hook2; end
end

# يجب على الأصناف المحسوسة تنفيذ جميع العمليات المجردة للصنف الأساسي.
# ويمكنها أيضًا إعادة تعريف بعض العمليات بتطبيق افتراضي.
class ConcreteClass1 < AbstractClass
  def required_operations1
    puts 'ConcreteClass1 says: Implemented Operation1'
  end

  def required_operations2
    puts 'ConcreteClass1 says: Implemented Operation2'
  end
end

# عادةً ما تُعيد الأصناف المحسوسة تعريف جزء يسير فقط من عمليات الصنف الأساسي.
class ConcreteClass2 < AbstractClass
  def required_operations1
    puts 'ConcreteClass2 says: Implemented Operation1'
  end

  def required_operations2
    puts 'ConcreteClass2 says: Implemented Operation2'
  end

  def hook1
    puts 'ConcreteClass2 says: Overridden Hook1'
  end
end

# تستدعي شيفرة العميل أسلوب القالب لتنفيذ الخوارزمية. ولا يتعيّن
# على شيفرة العميل معرفة الصنف المحسوس للكائن الذي تتعامل معه، طالما
# أنها تتعامل مع الكائنات عبر واجهة صنفها الأساسي.
def client_code(abstract_class)
  # ...
  abstract_class.template_method
  # ...
end

puts 'Same client code can work with different subclasses:'
client_code(ConcreteClass1.new)
puts "\n"

puts 'Same client code can work with different subclasses:'
client_code(ConcreteClass2.new)

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway
```

### rust

```rust
trait TemplateMethod {
    fn template_method(&self) {
        self.base_operation1();
        self.required_operations1();
        self.base_operation2();
        self.hook1();
        self.required_operations2();
        self.base_operation3();
        self.hook2();
    }

    fn base_operation1(&self) {
        println!("TemplateMethod says: I am doing the bulk of the work");
    }

    fn base_operation2(&self) {
        println!("TemplateMethod says: But I let subclasses override some operations");
    }

    fn base_operation3(&self) {
        println!("TemplateMethod says: But I am doing the bulk of the work anyway");
    }

    fn hook1(&self) {}
    fn hook2(&self) {}

    fn required_operations1(&self);
    fn required_operations2(&self);
}

struct ConcreteStruct1;

impl TemplateMethod for ConcreteStruct1 {
    fn required_operations1(&self) {
        println!("ConcreteStruct1 says: Implemented Operation1")
    }

    fn required_operations2(&self) {
        println!("ConcreteStruct1 says: Implemented Operation2")
    }
}

struct ConcreteStruct2;

impl TemplateMethod for ConcreteStruct2 {
    fn required_operations1(&self) {
        println!("ConcreteStruct2 says: Implemented Operation1")
    }

    fn required_operations2(&self) {
        println!("ConcreteStruct2 says: Implemented Operation2")
    }
}

fn client_code(concrete: impl TemplateMethod) {
    concrete.template_method()
}

fn main() {
    println!("Same client code can work with different concrete implementations:");
    client_code(ConcreteStruct1);
    println!();

    println!("Same client code can work with different concrete implementations:");
    client_code(ConcreteStruct2);
}

Same client code can work with different concrete implementations:
TemplateMethod says: I am doing the bulk of the work
ConcreteStruct1 says: Implemented Operation1
TemplateMethod says: But I let subclasses override some operations
ConcreteStruct1 says: Implemented Operation2
TemplateMethod says: But I am doing the bulk of the work anyway

Same client code can work with different concrete implementations:
TemplateMethod says: I am doing the bulk of the work
ConcreteStruct2 says: Implemented Operation1
TemplateMethod says: But I let subclasses override some operations
ConcreteStruct2 says: Implemented Operation2
TemplateMethod says: But I am doing the bulk of the work anyway
```

### swift

```swift
import XCTest


/// يُعرّف البروتوكول المجرد وامتداده أسلوب قالب يحتوي على هيكل
/// عام لخوارزمية ما، يتألف من استدعاءات لعمليات أولية مجردة
/// (عادةً).
///
/// على الأصناف الفرعية المحسوسة تنفيذ هذه العمليات، مع ترك
/// أسلوب القالب نفسه دون تغيير.
protocol AbstractProtocol {

    /// يُعرّف أسلوب القالب الهيكل العام للخوارزمية.
    func templateMethod()

    /// هذه العمليات تمتلك تطبيقات بالفعل.
    func baseOperation1()

    func baseOperation2()

    func baseOperation3()

    /// يجب تنفيذ هذه العمليات في الأصناف الفرعية.
    func requiredOperations1()
    func requiredOperation2()

    /// هذه "خطافات". قد تُعيد الأصناف الفرعية تعريفها، لكن ذلك ليس
    /// إلزاميًا لأن الخطافات تمتلك بالفعل تطبيقًا افتراضيًا (لكنه فارغ).
    /// توفّر الخطافات نقاط توسيع إضافية في بعض المواضع الحاسمة من
    /// الخوارزمية.
    func hook1()
    func hook2()
}

extension AbstractProtocol {

    func templateMethod() {
        baseOperation1()
        requiredOperations1()
        baseOperation2()
        hook1()
        requiredOperation2()
        baseOperation3()
        hook2()
    }

    /// هذه العمليات تمتلك تطبيقات بالفعل.
    func baseOperation1() {
        print("AbstractProtocol says: I am doing the bulk of the work\n")
    }

    func baseOperation2() {
        print("AbstractProtocol says: But I let subclasses override some operations\n")
    }

    func baseOperation3() {
        print("AbstractProtocol says: But I am doing the bulk of the work anyway\n")
    }

    func hook1() {}
    func hook2() {}
}

/// يجب على الأصناف المحسوسة تنفيذ جميع العمليات المجردة
/// للصنف الأساسي. ويمكنها أيضًا إعادة تعريف بعض العمليات بتطبيق افتراضي.
class ConcreteClass1: AbstractProtocol {

    func requiredOperations1() {
        print("ConcreteClass1 says: Implemented Operation1\n")
    }

    func requiredOperation2() {
        print("ConcreteClass1 says: Implemented Operation2\n")
    }

    func hook2() {
        print("ConcreteClass1 says: Overridden Hook2\n")
    }
}

/// عادةً ما تُعيد الأصناف المحسوسة تعريف جزء يسير فقط من
/// عمليات الصنف الأساسي.
class ConcreteClass2: AbstractProtocol {

    func requiredOperations1() {
        print("ConcreteClass2 says: Implemented Operation1\n")
    }

    func requiredOperation2() {
        print("ConcreteClass2 says: Implemented Operation2\n")
    }

    func hook1() {
        print("ConcreteClass2 says: Overridden Hook1\n")
    }
}

/// تستدعي شيفرة العميل أسلوب القالب لتنفيذ الخوارزمية. ولا
/// يتعيّن على شيفرة العميل معرفة الصنف المحسوس للكائن الذي تتعامل
/// معه، طالما أنها تتعامل مع الكائنات عبر واجهة صنفها الأساسي.
class Client {
    // ...
    static func clientCode(use object: AbstractProtocol) {
        // ...
        object.templateMethod()
        // ...
    }
    // ...
}


/// لنرَ كيف يعمل كل ذلك معًا.
class TemplateMethodConceptual: XCTestCase {

    func test() {

        print("Same client code can work with different subclasses:\n")
        Client.clientCode(use: ConcreteClass1())

        print("\nSame client code can work with different subclasses:\n")
        Client.clientCode(use: ConcreteClass2())
    }
}

Same client code can work with different subclasses:

AbstractProtocol says: I am doing the bulk of the work

ConcreteClass1 says: Implemented Operation1

AbstractProtocol says: But I let subclasses override some operations

ConcreteClass1 says: Implemented Operation2

AbstractProtocol says: But I am doing the bulk of the work anyway

ConcreteClass1 says: Overridden Hook2


Same client code can work with different subclasses:

AbstractProtocol says: I am doing the bulk of the work

ConcreteClass2 says: Implemented Operation1

AbstractProtocol says: But I let subclasses override some operations

ConcreteClass2 says: Overridden Hook1

ConcreteClass2 says: Implemented Operation2

AbstractProtocol says: But I am doing the bulk of the work anyway

import XCTest
import AVFoundation
import CoreLocation
import Photos

class TemplateMethodRealWorld: XCTestCase {

    /// مثال جيد على أسلوب القالب هو دورة حياة UIViewController

    func testTemplateMethodReal() {

        let accessors = [CameraAccessor(), MicrophoneAccessor(), PhotoLibraryAccessor()]

        accessors.forEach { item in
            item.requestAccessIfNeeded({ status in
                let message = status ? "You have access to " : "You do not have access to "
                print(message + item.description + "\n")
            })
        }
    }
}

class PermissionAccessor: CustomStringConvertible {

    typealias Completion = (Bool) -> ()

    func requestAccessIfNeeded(_ completion: @escaping Completion) {

        guard !hasAccess() else { completion(true); return }

        willReceiveAccess()

        requestAccess { status in
            status ? self.didReceiveAccess() : self.didRejectAccess()

            completion(status)
        }
    }

    func requestAccess(_ completion: @escaping Completion) {
        fatalError("Should be overridden")
    }

    func hasAccess() -> Bool {
        fatalError("Should be overridden")
    }

    var description: String { return "PermissionAccessor" }

    /// خطافات
    func willReceiveAccess() {}

    func didReceiveAccess() {}

    func didRejectAccess() {}
}

class CameraAccessor: PermissionAccessor {

    override func requestAccess(_ completion: @escaping Completion) {
        AVCaptureDevice.requestAccess(for: .video) { status in
            return completion(status)
        }
    }

    override func hasAccess() -> Bool {
        return AVCaptureDevice.authorizationStatus(for: .video) == .authorized
    }

    override var description: String { return "Camera" }
}

class MicrophoneAccessor: PermissionAccessor {

    override func requestAccess(_ completion: @escaping Completion) {
        AVAudioSession.sharedInstance().requestRecordPermission { status in
            completion(status)
        }
    }

    override func hasAccess() -> Bool {
        return AVAudioSession.sharedInstance().recordPermission == .granted
    }

    override var description: String { return "Microphone" }
}

class PhotoLibraryAccessor: PermissionAccessor {

    override func requestAccess(_ completion: @escaping Completion) {
        PHPhotoLibrary.requestAuthorization { status in
            completion(status == .authorized)
        }
    }

    override func hasAccess() -> Bool {
        return PHPhotoLibrary.authorizationStatus() == .authorized
    }

    override var description: String { return "PhotoLibrary" }

    override func didReceiveAccess() {
        /// نريد تتبّع عدد الأشخاص الذين يمنحون صلاحية الوصول إلى PhotoLibrary.
        print("PhotoLibrary Accessor: Receive access. Updating analytics...")
    }

    override func didRejectAccess() {
        /// ... وأيضًا نريد تتبّع عدد الأشخاص الذين رفضوا منح الصلاحية.
        print("PhotoLibrary Accessor: Rejected with access. Updating analytics...")
    }
}

You have access to Camera

You have access to Microphone

PhotoLibrary Accessor: Rejected with access. Updating analytics...
You do not have access to PhotoLibrary
```

### typescript

```typescript
/**
 * يُعرّف الصنف المجرد أسلوب قالب يحتوي على هيكل عام لخوارزمية ما،
 * يتألف من استدعاءات لعمليات أولية مجردة (عادةً).
 *
 * على الأصناف الفرعية المحسوسة تنفيذ هذه العمليات، مع ترك أسلوب
 * القالب نفسه دون تغيير.
 */
abstract class AbstractClass {
    /**
     * يُعرّف أسلوب القالب الهيكل العام للخوارزمية.
     */
    public templateMethod(): void {
        this.baseOperation1();
        this.requiredOperations1();
        this.baseOperation2();
        this.hook1();
        this.requiredOperation2();
        this.baseOperation3();
        this.hook2();
    }

    /**
     * هذه العمليات تمتلك تطبيقات بالفعل.
     */
    protected baseOperation1(): void {
        console.log('AbstractClass says: I am doing the bulk of the work');
    }

    protected baseOperation2(): void {
        console.log('AbstractClass says: But I let subclasses override some operations');
    }

    protected baseOperation3(): void {
        console.log('AbstractClass says: But I am doing the bulk of the work anyway');
    }

    /**
     * يجب تنفيذ هذه العمليات في الأصناف الفرعية.
     */
    protected abstract requiredOperations1(): void;

    protected abstract requiredOperation2(): void;

    /**
     * هذه "خطافات". قد تُعيد الأصناف الفرعية تعريفها، لكن ذلك ليس
     * إلزاميًا لأن الخطافات تمتلك بالفعل تطبيقًا افتراضيًا (لكنه فارغ).
     * توفّر الخطافات نقاط توسيع إضافية في بعض المواضع الحاسمة من
     * الخوارزمية.
     */
    protected hook1(): void { }

    protected hook2(): void { }
}

/**
 * يجب على الأصناف المحسوسة تنفيذ جميع العمليات المجردة للصنف الأساسي.
 * ويمكنها أيضًا إعادة تعريف بعض العمليات بتطبيق افتراضي.
 */
class ConcreteClass1 extends AbstractClass {
    protected requiredOperations1(): void {
        console.log('ConcreteClass1 says: Implemented Operation1');
    }

    protected requiredOperation2(): void {
        console.log('ConcreteClass1 says: Implemented Operation2');
    }
}

/**
 * عادةً ما تُعيد الأصناف المحسوسة تعريف جزء يسير فقط من عمليات الصنف الأساسي.
 */
class ConcreteClass2 extends AbstractClass {
    protected requiredOperations1(): void {
        console.log('ConcreteClass2 says: Implemented Operation1');
    }

    protected requiredOperation2(): void {
        console.log('ConcreteClass2 says: Implemented Operation2');
    }

    protected hook1(): void {
        console.log('ConcreteClass2 says: Overridden Hook1');
    }
}

/**
 * تستدعي شيفرة العميل أسلوب القالب لتنفيذ الخوارزمية. ولا يتعيّن
 * على شيفرة العميل معرفة الصنف المحسوس للكائن الذي تتعامل معه،
 * طالما أنها تتعامل مع الكائنات عبر واجهة صنفها الأساسي.
 */
function clientCode(abstractClass: AbstractClass) {
    // ...
    abstractClass.templateMethod();
    // ...
}

console.log('Same client code can work with different subclasses:');
clientCode(new ConcreteClass1());
console.log('');

console.log('Same client code can work with different subclasses:');
clientCode(new ConcreteClass2());

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway
```

