مُحدِّدات الوصول (Visibility Modifiers) في لغة Kotlin

من موسوعة حسوب

تُعيِّن مُحدِّدات الوصول قابليةَ الوصول إلى كلٍّ من الأصناف (classes) والكائنات (objects) والواجهات (interfaces) والدوال (functions) والخاصّيّات (properties) ودوال الوصول إليها من النوع setters (لأن مُحدِّد الوصول إلى getter مماثلٌ للوصول إلى الخاصّيّة نفسها)، وهناك أربعة أنواعٍ من المُحدِّدات وهي: private و protected و internal و public والنوع الافتراضيّ منها هو public (يُستخدم عند عدم وجود تصريحٍ عن إحداها)، وفيما يلي شرح لكيفيّة تطبيق المُحدِّدات على أنواعٍ مختلفةٍ من التصريحات (declarations).

الحزم (Packages)

يمكن تعريف كلٍّ من الدوال والخاصّيّات والأصناف والكائنات والواجهات في المستوى الأعلى (top-level) أيّ داخل الحزمة مباشرةً، مثل:

package foo

fun baz() {}
class Bar {}

ويُلاحظ ما يلي:

- إذا لم تُحدَّد مرئية الوصول فهي عامّة public بالحالة الافتراضيّة، وهذا يعني أنّ العنصر سيكون متاحًا بأيّ مكانٍ.

- تحديد المرئية بالنوع الخاصّ private سيجعل من العنصر مرئيًا داخل الملفّ (file) الذي يحتوي على تصريحه فقط.

- تحديد المرئية بالنوع internal سيجعل العنصر مرئيًا داخل الوحدة (module) ذاتها.

- ولا يًتاح النوع protected في التصريحات ذات المستوى الأعلى (top-level).

ملاحظة: لاستخدام أيّ تصريحٍ مرئيٍّ بالمستوى الأعلى (top-level) في حزمةٍ أخرى تستطيع استخدام أمر الاستيراد import للحصول عليه.

مثال:

// اسم الملف example.kt
package foo

private fun foo() {} // مرئي داخل الملف example.kt

public var bar: Int = 5 // الخاصية مرئية في كل مكان
    private set         // محدد الوصول هذا متاح فقط ضمن الملف example.kt
    
internal val baz = 6    // مرئي ضمن حدود الوحدة (module)

الأصناف (Classes) والواجهات (Interfaces)

عند التصريح عن العناصر المُعرَّفة داخل الأصناف تكون إحدى الحالات الآتية:

- مُحدِّد الوصول private: يعني أن العنصر مرئيٌّ داخل الصنف فقط (متضمنًا العناصر الأخرى الموجودة فيه).

- مُحدِّد الوصول protected: مثل مرئيّة المُحدِّد private ويُضاف عليه أن العنصر مرئيٌّ أيضًا في الأصناف الفرعيّة (subclasses) لهذا الصنف.

- مُحدِّد الوصول internal: إن أيّ عميلٍ (client) يستطيع الوصول للصنف الذي يحتوي على التصريحات (داخل هذه الوحدة [module]) يستطيع أيضًا رؤية العناصر الداخلية (internal) فيه.

- مُحدِّد الوصول public: إن أيّ عميلٍ (client) يستطيع الوصول للصنف الذي يحتوي على التصريحات يستطيع أيضًا رؤية العناصر العامّة (public) الموجودة فيه.

ملاحظة لمبرمجي Java: يختلف الأمر في Kotlin إذ إنّ الأصناف الخارجية (outer classes) لا تستطيع الوصول إلى أيّ من العناصر الخاصّة (private) الموجودة في أصنافها الداخلية (inner classes).

وعند إعادة تعريف عنصرٍ مُحدَّد بالوصول من النوع protected دون التحديد الصريح لمرئيّة الوصول له فإنّ المُحدِّد سيكون من النوع protected أيضًا.

مثال:

open class Outer {
    private val a = 1
    protected open val b = 2
    internal val c = 3
    val d = 4  // عامٌّ بالحالة الافتراضية
    
    protected class Nested {
        public val e: Int = 5
    }
}

class Subclass : Outer() {
    // a غير مرئية
    // bو c و d مرئية
    // e مرئية
    // Nested الصنف مرئي 

    override val b = 5   // من النوع المحمي protected
}

class Unrelated(o: Outer) {
    // o.a, o.b غير مرئية
    // o.c , o.d مرئية لأنها في نفس الوحدة 
    // Outer.Nested غير مرئي
    // Nested::e غير مرئية أيضًا 
}

البواني (Constructors)

تُستخدَم الصيغة الآتية لتحديد مرئية الباني الأساسي (primary constructor) في الصنف (لاحظ عدم وجود الكلمة المفتاحية constructor):

class C private constructor(a: Int) { ... }

إذ إنّ نوع الباني في الشيفرة السابقة من النوع الخاص (private) بسبب التصريح الواضح عن ذلك حيث أن الحالة الافتراضيّة للبواني هي العامّة (public) مما يجعلها مُتاحةً في كلّ مكانٍ يكون الصنف فيه مرئيًا (أي أن الباني الموجود في الصنف من النوع internal يكون مرئيًا في نفس الوحدة [module] فقط).

التصريحات المحلية (Local Declarations)

لا يمكن تحديد مرئيّة الوصول للتصريحات أو الدوال أو الأصناف المحليّة.

الوحدات (Modules)

إن مُحدِّد الوصول internal يعني أنّ هذا العنصر مرئيٌّ في نفس الوحدة الموجود فيها، وبكلامٍ أكثر دقةٍ؛ إنّ الوحدة هي مجموعةٌ من الملفات المكتوبة بلغة Kotlin والتي تُترجَم (compiled) سويةً مثل:

  • وحدة IntelliJ IDEA
  • مشروع Maven
  • مجموعةٌ مصدريةٌ (source set) في Gradle (باستثناء أنّ المجموعة المصدرية test تستطيع الوصول إلى التصريحات الداخليّة في main)
  • مجموعة الملفات المُترجَمة عبر استدعاءٍ واحدٍ لمهمة Ant.

مصادر