التعريف: يتضمن بعض العمليات التي تعمل على كل عنصر في بنية بيانات معينة. يمكن أن تحدد عمليات جديدة تعمل على هذه العناصر دون تغيير بنية البيانات.
النوع: نمط سلوكي
مخطط الفصل:
مثال:
على سبيل المثال ، فكر في إضافة أنواع مختلفة من البضائع إلى العربة ، وعند النقر فوق الخروج ، فإنه يحسب الرسوم المراد دفعها لجميع البضائع المختلفة. الآن ، يكون منطق الحساب هو حساب أسعار هذه الأنواع المختلفة من البضائع. أو بعبارة أخرى ، نقوم بنقل هذا المنطق إلى فئة أخرى من خلال وضع الزائر. دعونا ننفذ هذا المثال لنمط الزوار.
لتنفيذ نمط الزائر ، أول ما يجب فعله هو إنشاء فئة يمكن إضافتها إلى عربة التسوق لتمثيل أنواع مختلفة من العناصر (العناصر).
itemElement.javapackage com.journaldev.design.visitor ؛ الواجهة العامة itemElement {public int accounلاحظ أن طريقة القبول تقبل الزائر كمعلمة. بالطبع ، هناك طرق أخرى لتحديد منتجات مفصلة هنا ، ولكن من أجل البساطة ، ليست هناك حاجة للنظر في الكثير من التفاصيل هنا ، مع التركيز فقط على وضع الزوار.
الآن قم بإنشاء بعض فئات الكيانات لمنتجات مختلفة.
book.java
Package com.journaldev.design.visitor ؛ كتاب الطبقة العامة ينفذ itemElement {private int price ؛ سلسلة خاصة isbnnumber ؛ الكتاب العام (التكلفة int ، سلسلة ISBN) {this.price = cost ؛ this.isbnnumber = ISBN ؛ } public int getPrice () {return price ؛ } السلسلة العامة getisbnnumber () {return isBnnumber ؛ } Override public int (staringcartvisitor issitor) {return visitor.visit (this) ؛ }}الفاكهة
Package com.journaldev.design.visitor ؛ فاكهة الطبقة العامة تنفذ itemElement {private int priceperkg ؛ وزن int الخاص اسم السلسلة الخاصة ؛ الفاكهة العامة (int pricekg ، int wt ، string nm) {this.priceperkg = pricekg ؛ this.weight = wt ؛ this.name = nm ؛ } public int getPricePerkg () {return priceperkg ؛ } public int getweight () {return weight ؛ } السلسلة العامة getName () {return this.name ؛ } Override public int (staringcartvisitor issitor) {return visitor.visit (this) ؛ }} لاحظ أن تنفيذ طريقة القبول () موجود في فئة الكيان ، والتي تستدعي طريقة زيارة الزائر () لتمرير كائن الفئة الحالي كمعلمة خاصة به.
هنا ، سيتم تنفيذ طريقة Visit () المستخدمة لأنواع مختلفة من البضائع في فئة الكيان من واجهة الزوار.
التسوق Cartvisitor.java
Package com.journaldev.design.visitor ؛ public interface shoopcartvisitor {int visit (Book Book) ؛ زيارة int (فاكهة الفاكهة) ؛}سيتم الآن تنفيذ واجهة الزوار ومنطق حساب نفقاته الخاصة لكل منتج.
التسوق Cartvisitorimpl.java
Package com.journaldev.design.visitor ؛ Public Class ShoppingCartVisitorImpl تنفذ ShoppingCartVisitor {Override public int visit (كتاب) {int cost = 0 ؛ // تطبيق 5 دولارات خصم إذا كان سعر الكتاب أكبر من 50 إذا (book.getPrice ()> 50) {cost = book.getPrice ()-5 ؛ } تكلفة أخرى = book.getPrice () ؛ System.out.println ("Book ISBN ::"+book.getisBnnumber ()+"cost ="+cost) ؛ تكلفة العائد } override public int visit (fruit fruit) {int cost = fruit.getPricePerkg ()*fruit.getweight () ؛ system.out.println (fruit.getName () + "cost =" + cost) ؛ تكلفة العائد }}الآن دعونا نرى كيفية استخدامه في البرنامج.
التسوق Cartclient.java
package com.journaldev.design.visitor ؛ public class shorpingcartclient {public static void main (string [] args) {itemelement [] items = new itemelement [] {New Book (20 ، "1234") ، New Book (100 ، "5678") ، Fruit Fruit (10 ، 2 ، "Banana") ، Fruit Fruit (5 ، "5 ،" 5 ، " int total = calculatePrice (العناصر) ؛ System.out.println ("التكلفة الإجمالية ="+المجموع) ؛ } int static int private calculatePrice (itemElement [] items) {shoopcartvisitor visitor = new ShoppingCartVisitorImpl () ؛ int sum = 0 ؛ لـ (itemelement item: items) {sum = sum + item.accept (visitor) ؛ } إرجاع مجموع ؛ }}عند تشغيل البرنامج أعلاه ، نحصل على الإخراج التالي.
Book ISBN :: 1234 COST = 20Book ISBN :: 5678 COST = 95BANANA COST = 20Apple COST = 25TOTAL COST = 160
يرجى ملاحظة أن التنفيذ هنا يبدو أنه نفس طريقة قبول () لجميع المنتجات ، ولكن يمكن أن يكون مختلفًا أيضًا. على سبيل المثال ، إذا كان المنتج فارغًا ، فيمكنه إجراء فحوصات منطقية ولم يعد يستدعي طريقة Visit ().
مزايا وضع الزوار:
الامتثال لمبدأ المسؤولية الفردية: في أي سيناريو حيث يكون وضع الزائر قابلاً للتطبيق ، يجب أن تكون العمليات التي يجب تغليفها في الزائر في فئة العناصر لا علاقة لها بفئة العناصر نفسها وهي متقلبة. من ناحية ، يتوافق استخدام وضع الزائر مع مبدأ المسؤولية الفردية ، ومن ناحية أخرى ، لأن العمليات المغلفة عادة ما تكون متقلبة ، عندما تحدث التغييرات ، يمكن تحقيق توسيع الجزء المتغير دون تغيير فئة العناصر نفسها.
قابلية التوسع الجيدة: يمكن لفئات العناصر تمديد العمليات المختلفة من خلال قبول زوار مختلفين.
السيناريوهات المعمول بها لوضع الزوار:
إذا كانت هناك بعض العمليات في كائن لا يرتبط بالكائن (أو مرتبط بشكل ضعيف) ومن أجل تجنب هذه العمليات تلوث الكائن ، يمكنك استخدام وضع الزائر لتغليف هذه العمليات في الزائر.
إذا كانت هناك عمليات مماثلة في مجموعة من الكائنات ، من أجل تجنب عدد كبير من التعليمات البرمجية المكررة ، يمكن أيضًا تغليف هذه العمليات المكررة في الزائر.
ومع ذلك ، فإن وضع الزوار ليس مثاليًا ، كما أنه يحتوي على عيوب قاتلة: إضافة فئات العناصر الجديدة أكثر صعوبة. من خلال رمز نمط الزائر ، يمكننا أن نرى أنه في فئة الزوار ، يكون لكل فئة عناصر طريقة المعالجة المقابلة الخاصة بها. بمعنى أنه يجب إضافة كل فئة من العناصر لتعديل فئة الزوار (بما في ذلك الفئة الفرعية أو فئة التنفيذ في فئة الزوار) ، وهو أمر مزعج للغاية للتعديل. وهذا يعني أنه عندما يكون عدد فئات العناصر غير مؤكد ، يجب استخدام وضع الزائر بحذر. لذلك ، فإن وضع الزائر أكثر ملاءمة لإعادة إنشاء الوظائف الحالية. على سبيل المثال ، إذا تم تحديد الوظائف الأساسية للمشروع ، فقد تم تحديد بيانات فئات العناصر بشكل أساسي ولن تتغير. كل ما سيتغير هو العمليات ذات الصلة داخل هذه العناصر. في هذا الوقت ، يمكننا استخدام وضع الزوار لإعادة تشكيل الكود الأصلي ، بحيث يمكن تعديل الوظائف الأصلية دون تعديل كل فئة عناصر.
تلخيص:
نظرًا لأن GOF ، مؤلف نمط التصميم ، يصف وضع الزوار: في معظم الحالات ، تحتاج إلى استخدام وضع الزوار ، ولكن بمجرد أن تحتاج إليه ، فأنت بحاجة إليه حقًا. بالطبع هذا فقط للرجال الكبار الحقيقيين. في الواقع (على الأقل في البيئة التي أنا فيها) ، غالبًا ما يكون الكثير من الناس مدمنين على أنماط التصميم. عند استخدام نمط التصميم ، لا يفكرون بجدية في ما إذا كان النمط الذي يستخدمونه مناسبًا لهذا السيناريو ، ولكن في كثير من الأحيان يريدون فقط إظهار قدرتهم على التحكم في التصميم الموجهة للكائنات. إذا كان لديك هذه العقلية عند البرمجة ، فغالبًا ما تسيء استخدام نمط التصميم. لذلك ، عند تعلم أنماط التصميم ، يجب أن تفهم قابلية تطبيق الأنماط. من الضروري استخدام نمط لأنك تفهم مزاياه ، وليس استخدام نمط لأنك تفهم عيوبه ؛ بدلاً من استخدام نمط لأنك لا تفهم عيوبه ، وليس استخدام نمط لأنك لا تفهم مزاياه.