الاستخدام العملي لقالب الإستراتيجية

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

كيف تدرس أنماط التصميم؟ هناك طريقتان: مملة ومفهومة (هل تحب تصنيفاتي؟). ينطوي النهج الممل على الدراسة الأكاديمية لقائمة من الأنماط باستخدام أمثلة مجردة. أنا شخصياً أفضل العكس - نهج واضح ، عند تعيين المهمة على مستوى عالٍ نسبيًا من الصياغة يسمح لك باختيار أنماط التصميم. على الرغم من أنه يمكنك الجمع بين كلا النهجين.

إذن هيا بنا نذهب؟

يشير قالب الإستراتيجية إلى مجموعة من القوالب السلوكية.

تعريف موجز لنموذج الإستراتيجية


يعمل القالب على التبديل بين عائلة الخوارزميات عندما يقوم كائن بتغيير سلوكه بناءً على تغيير في حالته الداخلية.

أمثلة عملية لتطبيق قالب الإستراتيجية


  • الفرز: نريد فرز هذه الأرقام ، لكننا لا نعرف ما إذا كنا سنستخدم BrickSort أو BubbleSort أو أي فرز آخر. على سبيل المثال ، لديك موقع ويب تعرض فيه الصفحة عناصر بناءً على الشعبية. ومع ذلك ، يمكن أن تكون العديد من الأشياء "شائعة" (معظم المشاهدات ، معظم المشتركين ، تاريخ الإنشاء ، معظم النشاط ، أقل تعليق). في حالة عدم معرفة الإدارة بالضبط بعد كيفية تقديم طلب ، وقد ترغب في تجربة طلبات مختلفة في وقت لاحق ، يمكنك إنشاء واجهة (IOrderAlgorithm أو أي شيء آخر) باستخدام طريقة الطلب والسماح لكائن Orderer بتفويض ترتيب التنفيذ الملموس لواجهة IOrderAlgorithm . يمكنك إنشاء CommentOrderer و ActivityOrderer وما إلى ذلك ، وإيقاف تشغيلها ببساطة عند ظهور المتطلبات الجديدة.
  • معالجة قائمة انتظار من كائنات غير متجانسة (معالجة قائمة الانتظار وحفظ البيانات): من الأمثلة على ذلك نظام الوكيل الذي يقوم بتجميع الكائنات من مصادر بيانات مختلفة ، ثم بعد استخراج كائن من قائمة الانتظار ثم حفظه ، يتم تحديده من خلال استراتيجية التحديد بناءً على خصائص هذا الكائن.
  • التحقق نحتاج إلى التحقق من العناصر وفقًا لـ "بعض القواعد" ، ولكن لم يتضح بعد ما ستكون هذه القاعدة ، ويمكننا التفكير في عناصر جديدة.
  • المصادقة: حدد استراتيجية مصادقة بين مخططات Basic و Digest و OpenID و OAuth.

هنا مثال:

interface AuthStrategy {
    auth(): void;
}
class Auth0 implements AuthStrategy {
    auth() {
        log('Authenticating using Auth0 Strategy')
    }
}
class Basic implements AuthStrategy {
    auth() {
        log('Authenticating using Basic Strategy')
    }
}
class OpenID implements AuthStrategy {
    auth() {
        log('Authenticating using OpenID Strategy')
    }
}

class AuthProgram {
    private _strategy: AuthStrategy
    use(strategy: AuthStrategy) {
        this._strategy = strategy
        return this
    }
    authenticate() {
        if(this._strategy == null) {
            log("No Authentication Strategy set.")
        }
        this._strategy.auth()
    }
    route(path: string, strategy: AuthStrategy) {
        this._strategy = strategy
        this.authenticate()
        return this
    }
}

  • (games): — , , , , , , , . , , , , . «», «», «» Attack() . , «», «», «», « » Attack ().
  • (storing information): , , -. , PDF, , . , ; , , A, B C, . PDF , / PDF. , , , , , , B C, , A. , . PDF, , , . . Dependency Injection « / » ( , ), , , , , . , ( , ), , , , . « », «cleanUp» , , , , .
  • (outputting): X , CSV, XML, JSON .
  • (invoicing): - , , - .
  • (navigation): .
  • (logging): Log4Net Log4j , Appenders, Layouts, and Filters.
  • التشفير: بالنسبة للملفات الصغيرة ، يمكنك استخدام إستراتيجية الذاكرة الداخلية عند قراءة الملف بالكامل وتخزينه في الذاكرة (على سبيل المثال ، للملفات <1 غيغابايت). بالنسبة للملفات الكبيرة ، يمكنك استخدام إستراتيجية مختلفة حيث تتم قراءة أجزاء من الملف في الذاكرة ويتم تخزين النتائج المشفرة جزئيًا في ملفات tmp. يمكن أن تكون هذه استراتيجيتين مختلفتين لنفس المهمة.

هنا مثال:

//   ""
interface  Cipher  {
     public void performAction();
}

class InMemoryCipherStrategy implements Cipher { 
         public void performAction() {
             //   byte[] ....
         }
}

class SwaptToDiskCipher implements Cipher { 
         public void performAction() {
             //     .... 
         }

}

//   
File file = getFile();
Cipher c = CipherFactory.getCipher( file.size());
c.performAction();

  • محرر الرسوم البيانية: على سبيل المثال ، في تطبيق Windows Paint هناك تطبيق لقالب إستراتيجي يمكنك من خلاله تحديد الشكل واللون بشكل مستقل في أقسام مختلفة. هنا ، الشكل واللون خوارزميات يمكن تغييرها في وقت التشغيل.

Shape redCircle = new RedCircle(); //    «»
Shaped redCircle = new Shape("red","circle"); //   «»

سوليد وتنفيذ قالب الاستراتيجية


ما هي المشكلة الرئيسية التي يحلها قالب "الإستراتيجية"؟ في الواقع ، هذا بديل للرمز المسطح IF .... ذلك ... على تنفيذ هدفه.

مثال على كود مسطح قذر (خاطئ):

class Document {...}
class Printer {
    print(doc: Document, printStyle: Number) {
        if(printStyle == 0 /*   */) {
            // ...
        }
        if(printStyle == 1 /*  */) {
            // ...            
        }
        if(printStyle == 2 /*     */) {
            // ...
        }
        if(printStyle == 3 /*     */) {
            // ...            
        }
        if(printStyle == 4 /*     */) {
            // ...
        }
        // ...
    }
}

مثال على نفس الرمز مع قالب "الإستراتيجية" (بشكل صحيح):

class Document {...}
interface PrintingStrategy {
    printStrategy(d: Document): void;
}
class ColorPrintingStrategy implements PrintingStrategy {
    printStrategy(doc: Document) {
        log(" ")
        // ...
    }
}
class InvertedColorPrintingStrategy implements PrintingStrategy {
    printStrategy(doc: Document) {
        log("  ")
        // ...
    }
}
class Printer {
    private printingStrategy: PrintingStrategy
    print(doc: Document) {
        this.printingStrategy.printStrategy(doc)
    }
}

فيما يلي مثال آخر على التنفيذ الصحيح لقالب الإستراتيجية بناءً على SOLID.

//  /
interface LockOpenStrategy {
    open();
    lock();
}
//      
class RetinaScannerLockOpenStrategy implements LockOpenStrategy {
    open() {
        //...
    }
    lock() {
        //...
    }
}

//       
class KeypadLockOpenStrategy implements LockOpenStrategy {
    open() {
        if(password != ""){
            log("Entry Denied")
            return
        }
        //...
    }
    lock() {
        //...
    }
}
//        .
abstract class Door {
    public lockOpenStrategy: LockOpenStrategy
}
//   .
class GlassDoor extends Door {}
//    .
class MetalDoor extends Door {}
//       .
class DoorAdapter {
    openDoor(d: Door) {
        d.lockOpenStrategy.open()
    }
}

فيما يلي الترميز الفعلي للمنطق.

var glassDoor = new GlassDoor(); //   
glassDoor.lockOpenStrategy = new RetinaScannerLockOpenStrategy(); //         
var metalDoor = new MetalDoor(); //     
metalDoor.lockOpenStrategy = new KeypadLockOpenStrategy(); //      .
var door1 = new DoorAdapter().openDoor(glassDoor); //    . 
var door2  = new DoorAdapter().openDoor(metalDoor); //    . 

كما ترى أعلاه ، هذا رمز موجه بالكامل للكائن يستثني النمط الإجرائي IF .... ELSE ....... أو مفتاح ... قضية ...

بالمناسبة ، لماذا استخدمنا فئة المحول؟ لن يتم فتح الباب نفسه ، يتم فتحه دائمًا بشيء من جهة ، ومن ناحية أخرى يمكن أن تكون هناك بعض الأحداث التي تسبق فتح الباب أو عند الانتهاء من فتحه ، على سبيل المثال يمكن أن يكون BeforeOpen () و AfterOpen () مرتبطًا بـ مشترك كهربائي.

نموذج إعادة الهيكلة والإستراتيجية


يجب استخدام قالب الإستراتيجية عندما تبدأ في ملاحظة خوارزميات متكررة ، ولكن بأشكال مختلفة. وبالتالي ، من الضروري تقسيم الخوارزميات إلى فئات وملئها حسب الضرورة في برنامجك.

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

آمل أن يساعدك اختيار الأمثلة هذا في استخدام نموذج الإستراتيجية بشكل مناسب.
سأكون سعيدًا إذا كان بإمكانك تقديم المزيد من الأمثلة على هذا النموذج في التعليقات.

الترميز سعيدة والأصدقاء والزملاء!

Source: https://habr.com/ru/post/undefined/


All Articles