سؤال

هل يمكن لأي شخص أن يساعد في توضيح مبدأ انعكاس التبعية في جافا سكريبت مسج؟

والذي من شأنه أن يسلط الضوء على هاتين النقطتين ويشرحهما:

أ.لا ينبغي أن تعتمد الوحدات عالية المستوى على الوحدات ذات المستوى المنخفض.كلاهما يجب أن يعتمد على التجريدات.

ب.لا ينبغي أن تعتمد التجريدات على التفاصيل.التفاصيل يجب أن تعتمد على التجريدات.

ما هي التجريدات أو الوحدات عالية/منخفضة المستوى؟

وهذا سوف يساعد حقا في فهمي، وذلك بفضل!

هل كانت مفيدة؟

المحلول

أود أن أقول إن DIP ينطبق في JavaScript بنفس الطريقة التي يتم تطبيقه بها في معظم لغات البرمجة، ولكن عليك أن تكون على دراية بدور كتابة البطة.دعونا نفعل مثالا لمعرفة ما أعنيه ...

لنفترض أنني أريد الاتصال بالخادم للحصول على بعض البيانات.بدون تطبيق DIP، قد يبدو هذا كما يلي:

$.get("/address/to/data", function (data) {
    $("#thingy1").text(data.property1);
    $("#thingy2").text(data.property2);
});

مع DIP، قد أكتب رمزًا مثل

fillFromServer("/address/to/data", thingyView);

حيث التجريد fillFromServer يستطيع للحالة المحددة التي نريد فيها استخدام jQuery's Ajax يتم تنفيذها كما

function fillFromServer(url, view) {
    $.get(url, function (data) {
        view.setValues(data);
    });
}

والتجريد view يمكن تنفيذها لحالة معينة من العرض بناءً على العناصر ذات المعرفات thingy1 و thingy2 مثل

var thingyView = {
    setValues: function (data) {
        $("#thingy1").text(data.property1);
        $("#thingy2").text(data.property2);
    }
};

المبدأ أ:

  • fillFromServer ينتمي إلى وحدة نمطية منخفضة المستوى، حيث يتعامل مع التفاعل منخفض المستوى بين الخادم والعرض.شيء من هذا القبيل، على سبيل المثال، أ settingsUpdater سيكون الكائن جزءًا من وحدة نمطية ذات مستوى أعلى، وسيعتمد على fillFromServer التجريد --- ليس على تفاصيله، والتي يتم تنفيذها في هذه الحالة عبر jQuery.
  • بصورة مماثلة، fillFromServer لا يعتمد على تفاصيل عناصر DOM ومعرفاتها لأداء عملها؛بدلا من ذلك، فإنه يعتمد على تجريد أ view, ، وهو لأغراضه أي نوع له ملف setValues طريقة.(وهذا هو المقصود بـ "كتابة البطة".)

المبدأ ب:

هذا أقل سهولة في رؤيته في جافا سكريبت، مع كتابة البطة؛على وجه الخصوص، شيء من هذا القبيل view لا يشتق من (أيتعتمد على) نوع من viewInterface يكتب.لكن يمكننا القول أن مثالنا الخاص، thingyView, ، هو التفاصيل هذا "يعتمد" على التجريد view.

من الناحية الواقعية، فإن الأمر "يعتمد" على حقيقة أن المتصلين يفهمون نوع الأساليب التي يجب الاتصال بها، أي.أن المتصلين واعي من التجريد المناسب.في اللغات الموجهة للكائنات المعتادة، من الأسهل رؤية التبعية thingyView صراحة على التجريد نفسه.في مثل هذه اللغات، سيتم تجسيد التجريد في واجهة (على سبيل المثال، IView في C # أو Viewable في Java)، والتبعية الصريحة تكون عن طريق الميراث (class ThingyView : IView أو class ThingyView implements Viewable).ومع ذلك، ينطبق نفس الشعور.


لماذا هذا رائع؟حسنًا، لنفترض أنني في أحد الأيام كنت بحاجة إلى وضع بيانات الخادم في مربعات نصية ذات معرفات text1 و text2 بدلاً من <span />مع معرفات thingy1 و thingy2.علاوة على ذلك، لنفترض أنه تم استدعاء هذا الرمز في كثير من الأحيان، وكشفت المقارنة المعيارية عن فقدان الأداء المهم عبر استخدام jQuery.يمكنني بعد ذلك إنشاء "تنفيذ" جديد لـ view التجريد، مثل ذلك:

var textViewNoJQuery = {
   setValues: function (data) {
        document.getElementById("text1").value = data.property1;
        document.getElementById("text2").value = data.property2;
   }
};

ثم أقوم بإدخال هذا المثيل المحدد لتجريد العرض في ملفي fillFromServer التجريد:

fillFromServer("/address/to/data", textViewNoJQuery);

هذا مطلوب لا تغيير الى fillFromServer الكود، لأنه يعتمد فقط على تجريد a view مع setValues الطريقة، وليس على تفاصيل DOM وكيفية الوصول إليه.ليس هذا أمرًا مُرضيًا من حيث أنه يمكننا إعادة استخدام التعليمات البرمجية فحسب، بل يشير أيضًا إلى أننا قمنا بفصل مخاوفنا بشكل واضح وأنشأنا تعليمات برمجية مقاومة للمستقبل.

نصائح أخرى

يحرر:

يوضح هذا استخدام DIP في JavaScript الخام و أقل اكتمالا مثال مسج.ومع ذلك، يمكن تطبيق الوصف التالي بسهولة على jQuery.انظر مثال jQuery في الأسفل.

أفضل طريقة هي الاستفادة من "نمط المحول" - والذي يُطلق عليه أيضًا "المجمع".

يعد المحول في الأساس وسيلة لتغليف كائن أو وحدة نمطية بطريقة توفر نفس الشيء واجهة متسقة لها المعالين.بهذه الطريقة، يمكن للطبقة التابعة (عادةً أ مستوى أعلى class) يمكن بسهولة تبديل الوحدات من نفس النوع.

مثال على ذلك سيكون رفيع المستوى (أو أعلاه) الوحدة التي تعتمد على وحدات Geo/Mapping.

دعونا نحلل هذا.إذا كانت الوحدة أعلاه تستخدم GoogleMaps بالفعل ولكن بعد ذلك قررت الإدارة أن استخدام LeafletMaps أرخص - فلا نريد أن نضطر إلى إعادة كتابة كل استدعاء طريقة من gMap.showMap(user, latLong) ل leaflet.render(apiSecret,latLong, user), ، وآخرون.سيكون هذا كابوسًا إذا اضطررنا إلى نقل تطبيقنا من إطار عمل إلى آخر بهذه الطريقة.

ماذا نريد:نود الحصول على "غلاف" يوفر نفس الشيء واجهة متسقة إلى الوحدة أعلاه - وقم بذلك لكل وحدة المستوى الأدنى (أو الأشعة تحت الحمراء وحدة).

فيما يلي مثال بسيط مختلف:

var infra1 = (function(){
    function alertMessage(message){
        alert(message);
    }

    return {
        notify: alertMessage
    };
})();

var infra2 = (function(){
    function logMessage(message){
        console.log(message);
    }

    return {
        notify: logMessage
    };
})();


var Supra = function(writer){
    var notifier = writer;
    function writeMessage(msg){
        notifier.notify(msg);
    }

    this.writeNotification = writeMessage;
};


var supra;

supra = new Supra(infra1);
supra.writeNotification('This is a message');

supra = new Supra(infra2);
supra.writeNotification('This is a message');

لاحظ أنه بغض النظر عن نوع الوحدة ذات المستوى الأدنى "الكتابة" التي نستخدمها (في هذه الحالة infra1 و infra2)، ليس علينا إعادة كتابة أي من تنفيذ الوحدة عالية المستوى الخاصة بنا، Supra.وذلك لأن DIP يستفيد من مبدأين مختلفين لتصميم البرمجيات:"IoC" (انعكاس التحكم) و"DI" (حقن التبعية).

أفضل تشبيه صادفته هو الصورة الموضحة أدناه.

enter image description hereيعتمد كل مصدر كهربائي على واجهه المستخدم محددة لأنواع الأشياء التي تحتاج إلى توصيلها.

وصف مسج:

يمكن تطبيق هذا النمط بسهولة على استخدام أطر عمل مثل jQuery.أحد الأمثلة على ذلك هو مقبض DOM-Query البسيط.يمكننا استخدام DIP للسماح بالاقتران غير المحكم بحيث تكون الصيانة سهلة إذا قررنا تبديل الإطارات أو الاعتماد على أساليب DOM-Query الأصلية:

var jQ = (function($){

    return {
        getElement: $
    };
})(jQuery);

var nativeModule = (function(){

    return {
        getElement: document.querySelector
    };
})();


var SupraDOMQuery = function(api){
    var helper = api, thus = this;

    function queryDOM(selector){
        el = helper.getElement(selector);
        return thus;
    }

    this.get = queryDOM;
};


var DOM;

DOM = new SupraDOMQuery(jQ);
DOM.get('#id.class');

DOM = new SupraDOMQuery(nativeModule);
DOM.get('#id.class');

من الواضح أن هذا المثال سيحتاج إلى قدر أكبر من الوظائف حتى يكون عمليًا، ولكنني آمل أن يوصل الفكرة.

في الأساس، تصبح الاختلافات بين المحول والواجهة تافهة إلى حد ما.في الواجهة، ربما تنظر إلى وحدة نمطية واحدة تلتف حول واجهة برمجة التطبيقات (API) أو وحدة نمطية أخرى؛بينما يقوم المحول بإنشاء واجهة برمجة تطبيقات واجهة متسقة لكل وحدة من وحداته، ويستغل هذه التقنية لتجنب الاقتران الضيق.

معظم كتب أنماط تصميم جافا سكريبت تمر عبر نمط المحول؛الذي يمتد على وجه التحديد إلى "محول jQuery" هو تعلم أنماط تصميم جافا سكريبت بواسطة آدي عثماني نشرت من قبل أورايلي -- هنا.ومع ذلك، أنصح أيضًا بالبحث أنماط تصميم جافا سكريبت الاحترافية بواسطة داستن دياز وروس هارمز نشرت من قبل Apress -- تحقق من ذلك.ومع ذلك، أعتقد أنه من المهم فهم السياق الذي نخطط فيه لتنفيذ DIP فيما يتعلق بـ jQuery.

آمل أن يساعد هذا في توضيح الأمور :)

وجدت بعض الرسوم التوضيحية مفيدة هنا .

<اقتباس فقرة>

والتبعية مبدأ انعكاس في جافا سكريبت مسج

وليس هناك أي اتصال بين DI ومسج. DI هو كل شيء عن هيكل وتطبيق تجميع من compoents. مسج هو مجمع مفيد حول DOM، لا شيء أكثر من ذلك، لا يوجد لديه أي هيكل أو المكونات.

ويمكنك استخدام DI في التجمع تطبيق جافا سكريبت لديك، ولكن سيكون تبدو الى حد كبير نفس قيام بغض النظر عن استخدام مسج أم لا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top