JavaRush /مدونة جافا /Random-AR /معدّلات الوصول. خاص، محمي، افتراضي، عام

معدّلات الوصول. خاص، محمي، افتراضي، عام

نشرت في المجموعة
مرحبًا! في محاضرة اليوم سوف نتعرف على مفهوم " معدلات الوصول " ونلقي نظرة على أمثلة للعمل معهم. معدّلات الوصول.  خاص، محمي، افتراضي، عام - 1على الرغم من أن كلمة "دعونا نتعرف" لن تكون صحيحة تمامًا: فمعظمها مألوف بالفعل من المحاضرات السابقة. فقط في حالة، دعونا نقوم بتحديث ذاكرتنا حول الشيء الرئيسي. غالبًا ما تكون معدّلات الوصول عبارة عن كلمات رئيسية تنظم مستوى الوصول إلى أجزاء مختلفة من التعليمات البرمجية الخاصة بك. لماذا "في أغلب الأحيان"؟ نظرًا لأنه يتم تعيين أحدهما افتراضيًا ولا تتم الإشارة إليه بكلمة رئيسية :) يوجد إجمالي أربعة معدّلات وصول في Java. ندرجها بالترتيب من الأكثر صرامة إلى الأكثر "ناعمة":
  • خاص؛
  • محمي؛
  • الافتراضي (الحزمة مرئية)؛
  • عام
دعونا نلقي نظرة على كل واحد منهم، ونقرر متى يمكن أن تكون مفيدة لنا ونعطي أمثلة :)

المعدل خاص

معدّلات الوصول.  خاص، محمي، افتراضي، عام - 2Private- معدل الوصول الأكثر تقييدًا. فهو يحد من رؤية البيانات والأساليب داخل فئة واحدة. أنت تعرف هذا المعدل من المحاضرة حول الحروف والمستوطنين. تذكر هذا المثال؟
public class Cat {

   public String name;
   public int age;
   public int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }
}

public class Main {

   public static void main(String[] args) {

       Cat cat = new Cat();
       cat.name = "";
       cat.age = -1000;
       cat.weight = 0;
   }
}
لقد نظرنا إليها في إحدى المقالات السابقة. هنا ارتكبنا خطأً فادحًا: لقد فتحنا بياناتنا، ونتيجة لذلك كان لدى زملائنا المبرمجين إمكانية الوصول المباشر إلى حقول الفصل وتغيير قيمها. علاوة على ذلك، تم تعيين هذه القيم دون تدقيق، ونتيجة لذلك من الممكن في برنامجنا إنشاء قطة عمرها -1000 عام، واسم "" ووزن 0. لحل هذه المشكلة، قمنا تستخدم الحروف والمستوطنين ، كما أنها محدودة الوصول إلى البيانات باستخدام المعدل private.
public class Cat {

   private String name;
   private int age;
   private int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Meow!");
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       // checking the input parameter
       this.name = name;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       // checking the input parameter
       this.age = age;
   }

   public int getWeight() {
       return weight;
   }

   public void setWeight(int weight) {
       // checking the input parameter
       this.weight = weight;
   }
}
في الواقع، تقييد الوصول إلى الحقول وتنفيذ أدوات ضبط الحروف هو المثال الأكثر شيوعًا للاستخدام privateفي العمل الحقيقي. أي أن تنفيذ التغليف في البرنامج هو الغرض الرئيسي من هذا المعدل. بالمناسبة، هذا لا ينطبق فقط على الحقول. تخيل أنه يوجد في برنامجك طريقة تنفذ بعض الوظائف المعقدة جدًا. للتوصل إلى هذا كمثال... لنفترض أن طريقتك readDataFromCollider()تأخذ عنوانًا يحتوي على بيانات كمدخلات، وتقرأ البيانات من مصادم الهادرونات الكبير بتنسيق بايت، وتحول هذه البيانات إلى نص، وتكتبها في ملف وتطبعها. حتى وصف الطريقة يبدو مخيفًا، ناهيك عن الكود :) لزيادة سهولة قراءة الكود، سيكون من الجيد عدم كتابة المنطق المعقد للطريقة في مكان واحد، ولكن على العكس من ذلك، كسر الوظيفة إلى أساليب منفصلة. على سبيل المثال، الطريقة readByteData()مسؤولة عن قراءة البيانات، convertBytesToSymbols()وتحويل البيانات المقروءة من المصادم إلى نص، saveToFile()وحفظ النص الناتج في ملف، وطباعة printColliderData()ملف البيانات الخاص بنا. ستكون الطريقة readDataFromCollider()في النهاية أبسط بكثير:
public class ColliderUtil {

   public void readDataFromCollider(Path pathToData) {
       byte[] colliderData = readByteData(pathToData);
       String[] textData = convertBytesToSymbols(colliderData);
       File fileWithData = saveToFile(textData);
       printColliderData(fileWithData);
   }

   public byte[] readByteData(Path pathToData) {

       // reads data in bytes
   }

   public String[] convertBytesToSymbols(byte[] colliderDataInBytes) {

       // convert bytes to characters
   }

   public File saveToFile(String[] colliderData) {

       // save the read data to a file
   }

   public void printColliderData(File fileWithColliderData) {

       // print data from file
   }
}
ومع ذلك، كما تتذكر من المحاضرة حول الواجهات، فإن المستخدم يحصل فقط على الوصول إلى الواجهة النهائية. وأساليبنا الأربعة ليست جزءًا منه. إنها مساعدة : لقد أنشأناها لتحسين إمكانية قراءة التعليمات البرمجية ولتجنب حشر أربع مهام مختلفة في طريقة واحدة. ليست هناك حاجة لمنح المستخدم حق الوصول إلى هذه الأساليب. إذا كان لدى المستخدم حق الوصول إلى الطريقة عند العمل مع المصادم convertBytesToSymbols()، فمن المرجح أنه لن يفهم ببساطة ما هي هذه الطريقة وسبب الحاجة إليها. ما بايت يتم تحويلها؟ من أين أتوا؟ لماذا تحويلها إلى نص؟ المنطق الذي يتم تشغيله في هذه الطريقة ليس جزءًا من واجهة المستخدم. الطريقة فقط readDataFromCollider()هي جزء من الواجهة. ماذا تفعل بهذه الأساليب الأربعة "الداخلية"؟ يمين! تقييد الوصول إليهم باستخدام المُعدِّل private. وبهذه الطريقة يمكنهم القيام بعملهم بسهولة داخل الفصل وعدم إرباك المستخدم الذي لا يحتاج إلى منطق كل منهم على حدة.
public class ColliderUtil {

   public void readDataFromCollider(Path pathToData) {
       byte[] colliderData = readByteData(pathToData);
       String[] textData = convertBytesToSymbols(colliderData);
       File fileWithData = saveToFile(textData);
       printColliderData(fileWithData);
   }

   private byte[] readByteData(Path pathToData) {
       // reads data in bytes
   }

   private String[] convertBytesToSymbols(byte[] colliderDataInBytes) {
       // convert bytes to characters
   }

   private File saveToFile(String[] colliderData) {
       // save the read data to a file
   }

   private void printColliderData(File fileWithColliderData) {
       // print data from file
   }
}

المعدل محمي

معدّل الوصول التالي الأكثر تقييدًا هو protected. ستكون معدّلات الوصول.  خاص، محمي، افتراضي، عام - 3 الحقول والطرق المخصصة لتعديل الوصول مرئية:protected
  • ضمن جميع الفئات الموجودة في نفس الحزمة التي نقدمها؛
  • ضمن جميع الطبقات اللاحقة لطبقتنا.
من الصعب على الفور أن نتخيل متى قد تكون هناك حاجة لذلك. لا تتفاجأ: protectedهناك حالات تطبيق أقل بكثير من private, وهي محددة. تخيل أن لدينا فئة مجردة AbstractSecretAgentتشير إلى عميل سري لبعض وكالات الاستخبارات، بالإضافة إلى حزمة top_secretتحتوي على هذه الفئة وأحفادها. يتم توريث الطبقات الخرسانية - FBISecretAgent، وما MI6SecretAgentإلى MossadSecretAgentذلك - منها. داخل فئة مجردة نريد تنفيذ عداد وكيل. عندما يتم إنشاء كائن وكيل جديد في مكان ما في البرنامج، فإنه سيزيد.
package top_secret;

public abstract class AbstractSecretAgent {

   public static int agentCount = 0;
}
لكن وكلائنا سريون! هذا يعني أنهم وحدهم ولا ينبغي لأي شخص آخر أن يعرف عددهم. يمكننا بسهولة إضافة مُعدِّل protectedإلى الحقل agentCount، وبعد ذلك يمكن لكائنات فئات العملاء السريين الأخرى، أو تلك الفئات الموجودة في الحزمة "السرية"، الحصول على قيمتها top_secret.
public abstract class AbstractSecretAgent {

   protected static int agentCount = 0;
}
لمثل هذه المهام المحددة هناك حاجة إلى معدل protected:)

الحزمة المرئية المعدلة

التالي في قائمتنا هو المُعدِّل defaultأو، كما يطلق عليه أيضًا، package visible. لا تتم الإشارة إليه بكلمة أساسية لأنه تم تعيينه افتراضيًا في Java لجميع الحقول والأساليب. إذا كتبت في الكود الخاص بك -
int x = 10;
... سيكون للمتغير xنفس package visibleالوصول. إذا لم يتم تمييز الطريقة (أو المتغير) بأي معدل، فسيتم اعتبارها مميزة بـ "المعدل الافتراضي". المتغيرات أو الأساليب التي تحتوي على مثل هذا المعدل (أي بدون أي منها على الإطلاق) تكون مرئية لجميع فئات الحزمة التي تم الإعلان عنها. ولهم فقط. استخداماته محدودة، تمامًا مثل المُعدِّل protected. في أغلب الأحيان، defaultيتم استخدام -access في حزمة حيث توجد بعض فئات الأدوات المساعدة التي لا تنفذ وظائف جميع الفئات الأخرى في هذه الحزمة. دعونا نعطي مثالا. تخيل أن لدينا حزمة " الخدمات ". يوجد بداخله فئات مختلفة تعمل مع قاعدة البيانات. على سبيل المثال، هناك فئة UserServiceتقرأ بيانات المستخدم من قاعدة بيانات، وفئة CarServiceتقرأ البيانات المتعلقة بالسيارات من نفس قاعدة البيانات، وفئات أخرى، تعمل كل منها مع نوع الكائنات الخاص بها وتقرأ البيانات عنها من قاعدة البيانات.
package services;

public class UserService {
}

package services;

public class CarService {
}
ومع ذلك، يمكن أن يحدث موقف بسهولة عندما تكون البيانات الموجودة في قاعدة البيانات بتنسيق واحد، ولكننا نحتاج إليها بتنسيق آخر. تخيل أن تاريخ ميلاد المستخدم في قاعدة البيانات مخزن بالتنسيق TIMESTAMP With TIME ZONE...
2014-04-04 20:32:59.390583+02
...نحتاج بدلاً من ذلك إلى أبسط كائن - java.util.Date. لهذا الغرض، يمكننا إنشاء servicesفئة خاصة داخل الحزمة Mapper. سيكون مسؤولاً عن تحويل البيانات من قاعدة البيانات إلى كائنات Java التي نعرفها. فئة مساعد بسيط. عادةً ما نقوم بإنشاء جميع الفئات كـ public class ClassName، لكن هذا ليس ضروريًا. يمكننا أن نعلن عن فئة المساعد لدينا ببساطة كـ class Mapper. في هذه الحالة، فإنه لا يزال يؤدي وظيفته، لكنه غير مرئي لأي شخص خارج الحزمة services!
package services;

class Mapper {
}


package services;

public class CarService {

   Mapper mapper;
}
وهذا، في الواقع، هو المنطق الصحيح: لماذا يرى شخص ما خارج الحزمة فئة مساعدة تعمل فقط مع فئات من نفس الحزمة؟

المعدل العام

والأخير في القائمة، وليس آخرًا - المُعدِّل public! لقد التقيت به في اليوم الأول من الدراسة في JavaRush، حيث تم إطلاق public static void main(String[] args). معدّلات الوصول.  خاص، محمي، افتراضي، عام - 4 الآن بعد أن درست المحاضرات حول الواجهات، أصبح الغرض منها واضحًا لك :) بعد كل شيء، publicتم إنشاؤها من أجل تقديم شيء ما للمستخدمين. على سبيل المثال، واجهة البرنامج الخاص بك. لنفترض أنك كتبت برنامج مترجم، ويمكنه ترجمة النص الروسي إلى اللغة الإنجليزية. لقد قمت بإنشاء طريقة translate(String textInRussian)يتم من خلالها تنفيذ المنطق الضروري. لقد قمت بتمييز هذه الطريقة بالكلمة public، والآن ستصبح جزءًا من الواجهة:
public class Translator {

   public String translate(String textInRussian) {

       // translates text from Russian to English
   }
}
يمكنك ربط مكالمة بهذه الطريقة مع زر "الترجمة" الموجود على شاشة البرنامج - وهذا كل شيء! يمكن لأي شخص استخدامه. أجزاء الكود المميزة بالمعدل publicمخصصة للمستخدم النهائي. ولإعطاء مثال من الحياة، privateهذه هي جميع العمليات التي تحدث داخل التلفزيون عندما يعمل، وهذه publicهي الأزرار الموجودة على جهاز التحكم عن بعد الخاص بالتلفزيون والتي يمكن للمستخدم التحكم بها. وفي الوقت نفسه، لا يحتاج إلى معرفة كيفية عمل التلفزيون وكيف يعمل. جهاز التحكم عن بعد عبارة عن مجموعة publicمن الطرق: , on(), off(), nextChannel(), previousChannel()إلخ . increaseVolume()decreaseVolume()
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION