Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

الحقول المصدرة وغير المصدرة

جزء من قسم Object Oriented Programming في رحلة GO على Coddy — الدرس 47 من 107.

في لغة Go، يتم التحكم في التغليف (encapsulation) على مستوى الـ struct من خلال حالة الأحرف لأسماء الحقول. تحدد هذه القاعدة البسيطة ما إذا كان يمكن الوصول إلى الحقول من خارج الـ package التي تم تعريف الـ struct فيها.

الحقول التي تبدأ بـ حرف كبير تكون مُصدّرة—يمكن الوصول إليها من أي حزمة. الحقول التي تبدأ بـ حرف صغير تكون غير مُصدّرة—يمكن الوصول إليها فقط داخل نفس الحزمة:

// في الحزمة "user"
type User struct {
    Name     string  // مُصدّر - يمكن الوصول إليه من كل مكان
    Email    string  // مُصدّر - يمكن الوصول إليه من كل مكان
    password string  // غير مُصدّر - يمكن الوصول إليه فقط داخل الحزمة "user"
    age      int     // غير مُصدّر - يمكن الوصول إليه فقط داخل الحزمة "user"
}

عندما تقوم حزمة أخرى باستيراد واستخدام هذا الـ struct، فإنها لا تستطيع التفاعل إلا مع الحقول المصدرة (exported fields):

// في الحزمة "main"
import "user"

func main() {
    u := user.User{
        Name:  "Alice",      // يعمل
        Email: "a@mail.com", // يعمل
        // password: "secret", // خطأ في التجميع: حقل غير معروف
    }
    
    fmt.Println(u.Name)     // يعمل
    // fmt.Println(u.password) // خطأ في التجميع: لا يمكن الرجوع إلى حقل غير مصدر
}

تحمي هذه الآلية البيانات الحساسة وتفاصيل التنفيذ الداخلية. لا يمكن قراءة حقل password أو تعديله مباشرة من خارج الحزمة، مما يجبر الأكواد الأخرى على استخدام الأساليب (methods) التي توفرها. هذا هو نهج لغة Go لتحقيق إخفاء البيانات - وهو مبدأ أساسي للتغليف (encapsulation) في البرمجة كائنية التوجه.

challenge icon

التحدي

سهل

دعنا نبني نظام حساب بنكي يوضح مفهوم التغليف (encapsulation) من خلال الحقول المصدرة (exported) وغير المصدرة (unexported). ستقوم بإنشاء حزمة تحمي البيانات المالية الحساسة مع عرض المعلومات العامة الآمنة.

ستقوم بتنظيم الكود الخاص بك عبر ملفين:

  • account.go: قم بإنشاء هيكل BankAccount في حزمة main يمثل حساباً بنكياً حقيقياً مع حماية مناسبة للبيانات:
    • HolderName (مصدر - exported) - اسم صاحب الحساب، وهو آمن للعرض علناً
    • AccountType (مصدر - exported) - نوع الحساب (مثل "Savings"، "Checking")
    • balance (غير مصدر - unexported) - الرصيد الفعلي، والذي يجب أن يكون محمياً
    • pin (غير مصدر - unexported) - رمز PIN الخاص بالحساب، وهي بيانات حساسة للغاية
    أضف دالة منشئة (constructor) باسم NewBankAccount تأخذ اسم صاحب الحساب، ونوع الحساب، والرصيد الأولي، ورمز PIN، ثم تعيد مؤشراً (pointer) إلى BankAccount جديد. أضف أيضاً تابعاً (method) باسم GetPublicInfo() string يعيد التنسيق التالي: Account: [HolderName] ([AccountType])
  • main.go: اقرأ تفاصيل الحساب من المدخلات، وأنشئ BankAccount باستخدام المنشئ، ووضح عملية التغليف. اطبع المعلومات العامة باستخدام التابع، ثم قم بالوصول مباشرة إلى كل حقل مصدر واطبعه في أسطر منفصلة. الحقول غير المصدرة (balance و pin) محمية—يمكنك فقط تعيينها من خلال المنشئ.

سيتم توفير المدخلات التالية:

  • السطر 1: اسم صاحب الحساب
  • السطر 2: نوع الحساب
  • السطر 3: الرصيد الأولي (كعدد عشري float)
  • السطر 4: رمز PIN

على سبيل المثال، إذا كانت المدخلات Alice Johnson، Savings، 5000.50، و 1234، يجب أن يكون مخرجك:

Account: Alice Johnson (Savings)
Holder: Alice Johnson
Type: Savings

لاحظ أن الرصيد ورمز PIN لا يظهران أبداً في المخرجات—فهما مخفيان بأمان داخل الهيكل، ولا يمكن الوصول إليهما إلا داخل الحزمة. هذا هو التغليف في أبهى صوره: البيانات الحساسة محمية بينما تظل المعلومات العامة متاحة.

ورقة مرجعية

في لغة Go، يتم التحكم في التغليف (encapsulation) من خلال حالة الأحرف لأسماء الحقول في الهياكل (structs):

  • الحقول التي تبدأ بـ أحرف كبيرة (Uppercase) تكون مُصدرة (exported) (يمكن الوصول إليها من أي حزمة)
  • الحقول التي تبدأ بـ أحرف صغيرة (Lowercase) تكون غير مُصدرة (unexported) (يمكن الوصول إليها فقط داخل نفس الحزمة)
type User struct {
    Name     string  // مُصدرة - يمكن الوصول إليها من أي مكان
    Email    string  // مُصدرة - يمكن الوصول إليها من أي مكان
    password string  // غير مُصدرة - يمكن الوصول إليها فقط في نفس الحزمة
    age      int     // غير مُصدرة - يمكن الوصول إليها فقط في نفس الحزمة
}

عند استخدام هيكل (struct) من حزمة أخرى، يمكن الوصول فقط إلى الحقول المُصدرة:

import "user"

func main() {
    u := user.User{
        Name:  "Alice",      // تعمل
        Email: "a@mail.com", // تعمل
        // password: "secret", // خطأ في التجميع: حقل غير معروف
    }
    
    fmt.Println(u.Name)     // تعمل
    // fmt.Println(u.password) // خطأ في التجميع: لا يمكن الإشارة إلى حقل غير مُصدر
}

تحمي هذه الآلية البيانات الحساسة وتفاصيل التنفيذ الداخلية، مما يجبر الكود الخارجي على استخدام الأساليب (methods) المتوفرة للوصول.

جرّب بنفسك

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// قراءة اسم صاحب الحساب
	holderName, _ := reader.ReadString('\n')
	holderName = strings.TrimSpace(holderName)

	// قراءة نوع الحساب
	accountType, _ := reader.ReadString('\n')
	accountType = strings.TrimSpace(accountType)

	// قراءة الرصيد الأولي
	balanceStr, _ := reader.ReadString('\n')
	balanceStr = strings.TrimSpace(balanceStr)
	balance, _ := strconv.ParseFloat(balanceStr, 64)

	// قراءة الـ PIN
	pinStr, _ := reader.ReadString('\n')
	pin := strings.TrimSpace(pinStr)

	// TODO: إنشاء BankAccount جديد باستخدام الـ constructor
	// account := NewBankAccount(...)

	// TODO: طباعة المعلومات العامة باستخدام طريقة GetPublicInfo()

	// TODO: طباعة اسم صاحب الحساب من خلال الوصول مباشرة إلى الحقل المصدر (exported field)
	// fmt.Println("Holder:", ...)

	// TODO: طباعة نوع الحساب من خلال الوصول مباشرة إلى الحقل المصدر (exported field)
	// fmt.Println("Type:", ...)

	// Note: الحقلان balance و pin غير مصدرين (unexported) - لا يمكن الوصول إليهما مباشرة هنا
	// لقد تم تغليفهما (encapsulated) بأمان داخل الـ struct

	_ = balance // قم بإزالة هذا السطر عند استخدام balance
	_ = pin     // قم بإزالة هذا السطر عند استخدام pin
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming