مُحدِّدات الوصول (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.