CodeGym /Kurslar /C# SELF /Access modifier-lərlə və inkapsulyasiya ilə bağlı səhvlər...

Access modifier-lərlə və inkapsulyasiya ilə bağlı səhvlər

C# SELF
Səviyyə, Dərs
Mövcuddur

1. Giriş

Access modifier-lər — evindəki hasar və qıfıllar kimidir: kim hansı otağa girə bilər, kim isə sadəcə açardan baxa bilər, bunu müəyyən edir. Xatırladaq ki, C#-da bunlar belədir:

Modifier Kim görə bilər
public
Hamı
private
Yalnız cari class daxilində
protected
Cari class və miras alanlar
internal
Bütün layihə (assembly)
protected internal
Bütün layihə + miras alanlar
private protected
Yalnız bu layihədəki miras alanlar

İnkapsulyasiyanın məqsədi — class-ın implementasiya detallarını gizlətməkdir ki, heç kim sənin obyektini belə bir ifadə ilə korlaya bilməsin: obj.Field = 99999;, əgər sən bunu istəmirsənsə.

2. Access səviyyəsi ilə klassik səhvlər

Hər şeyi public etmək

Ən yayılmış səhv — class-ın bütün field və method-larını public kimi elan etməkdir. Məntiq belədir: "Bəlkə lazım olar? Qoy başqaları istədiyi yerdə mənim üzvlərimə müraciət etsin!". Bu yanaşma rahat görünür, ta ki, kimsə sənin obyektinə icazəsiz vəziyyət verməyənə və ya birdən-birə sənin daxili detallarını elə istifadə etməyə başlamayana qədər ki, kodu dəyişmək qorxulu olur.

Səhv nümunəsi:


public class BankAccount
{
    public string Owner;
    public decimal Balance;
}

İndi istənilən adam belə edə bilər:


var acc = new BankAccount();
acc.Owner = "";
acc.Balance = -1000000M; // Birdən-birə, milyon borc!

Nə səhvdir?
Sən bütün təhlükəsizlik və məntiq prinsiplərini pozdun. Hətta bankında yalnız ağac yarpaqları və ya "Monopoliya" oyunundan rəngli kağızlar olsa belə, "istəyə görə" mənfi balans — qəribədir.

Class-ı "structure-siz structure"ə çevirmək

İkinci tipik səhv — yalnız field-ları yox, həm də ümumiyyətlə xaricə açılmamalı olan daxili property və method-ları public etməkdir.


public class Vault
{
    public string DoorPIN = "1234";
    public void OpenDoor() 
    {
        // Hansısa magiya
    }
}

İndi nə oldu? İndi istənilən adam PIN-i öyrənib seyfin qapısını aça bilər. Hətta bu "test seyfi" olsa belə, bir ay sonra kimsə bu dəliyi unudacaq və xoşagəlməz hadisə baş verəcək.

Düzgün yanaşma:
Class-ın interfeysi minimal və qorunan olmalıdır. Başqalarına lazım olanı — public edirik. Yalnız özümüzə lazım olanı — private. Nəsillərə lazımdırsa — protected.

3. İnkapsulyasiya səhvləri

.NET-də sərt qayda var: heç bir class datası (state) public field-larda saxlanmamalıdır! Hər şey ya bağlı olmalı, ya da ən azı property-lə bükülməlidir. Field-lara birbaşa çıxış — pis stilin klassikası və çətin tapılan səhvlərin mənbəyidir.

Niyə field-lar private olmalıdır

Field-lar obyektin daxili vəziyyətinin əsasını təşkil edir. Əgər onlara public çıxış versən, nə vaxt və hansı dəyərlərin ora yazılacağını itirirsən. Obyektin səhv dəyərlərə qarşı həssas olur, formatı dəyişəndə isə bütün public müraciətlər pozulur.

Bunun əvəzinə:
Field-ları private elan et, xaricə yalnız lazım olan property və ya method-ları ver:


public class BankAccount
{
    private decimal balance;

    public decimal Balance
    {
        get { return balance; }
        private set 
        {
            if (value < 0) 
                throw new ArgumentException("Balans mənfi ola bilməz");
            balance = value;
        }
    }

    public BankAccount(decimal initialBalance)
    {
        Balance = initialBalance;
    }

    public void Deposit(decimal amount)
    {
        if (amount <= 0) throw new ArgumentException("Sıfır və ya az məbləğ əlavə etmək olmaz!");
        Balance += amount;
    }
}

Kobud səhv: public set dəyişmək olmazsa belə

Bəzən yalnız get lazımdır, amma proqramçılar "tez olsun" deyə public { get; set; } yazırlar. Nəticədə istənilən adam belə edə bilər:


account.Balance = 99999999; // Niyə də yox?

Daha düzgün:
Əgər property yalnız class daxilində dəyişməlidirsə, set-ə modifier ver:


public decimal Balance { get; private set; }

və ya, dəyər yalnız obyekt yaradılarkən təyin olunmalıdırsa (C# 14):


public decimal Balance { get; init; }

4. protected də bəzən tələdir

Bütün miras alanlara açıq qapılar

protected — funksionallığı miras alana ötürmək üçün yaxşı üsuldur, amma bəzi dataları hətta miras alanlara da açmaq olmaz! Məsələn, əgər sənin "uşaqların" (class-ın miras alanları) kritik field-ları birbaşa dəyişməməlidirsə.

Nümunə:


public class SecureVault
{
    protected string secretCode = "1234";
}

İndi istənilən miras alan belə edə bilər:


public class HackerVault : SecureVault
{
    public void Hack()
    {
        secretCode = "0000"; // Asanlıqla sirri dəyişdi!
    }
}

Tövsiyə:
protected-i yalnız həqiqətən miras alanlara lazım olan şeylər üçün istifadə et. Qalan hər şeyi private saxla, lazım olan əməliyyatlar üçün isə qorunan method-lar yaz.

5. internal ilə səhvlər və qarışıq assembly-lər

internal modifier-i cazibədar görünür: "qoy hər şey layihə daxilində əlçatan olsun". Amma layihə bir fayldan böyük olanda və ya kitabxanalar qoşulanda konfliktlər yaranır. Tez-tez tələbələr təsadüfən nəyisə layihə daxilində public edirlər, halbuki class tamamilə gizli olmalı idi.

Nümunə:


internal class Logger
{
    internal void Write(string msg) { /* ... */ }
}

İndi istənilən adam layihənin istənilən faylından Logger.Write çağıracaq. Bir il sonra kimsə sənin DLL-ni başqa layihəyə qoşsa? Bütün "daxili mətbəx" görünəcək, əgər nəyisə public qoymusan.

Məsləhət:
Texniki class-lar üçün internal istifadə et, amma həssas detallar yenə də private olsun.

6. Praktika: bank tətbiqi

Bank tətbiqi nümunəmizlə davam edirik ki, praktikada necə asan səhv etmək və bununla necə mübarizə aparmaq olar, görək.

Səhv nümunəsi №1: Public field-lar


public class BankAccount
{
    public decimal Balance;
    public string Owner;
}

Problem: istənilən adam bunu poza bilər.

Property-lərlə düzəldirik


public class BankAccount
{
    private decimal _balance;
    private string _owner;

    public string Owner => _owner; // Yalnız oxumaq üçün

    public decimal Balance 
    { 
        get => _balance; 
        private set 
        {
            if (value < 0) throw new ArgumentException("Balans mənfi ola bilməz");
            _balance = value;
        }
    }

    public BankAccount(string owner, decimal initialBalance)
    {
        if (string.IsNullOrWhiteSpace(owner))
            throw new ArgumentException("Sahibin adı vacibdir");

        _owner = owner;
        Balance = initialBalance;
    }

    public void Deposit(decimal amount)
    {
        if (amount <= 0)
            throw new ArgumentException("Əlavə olunan məbləğ müsbət olmalıdır");
        Balance += amount;
    }
}

İndi belə etməyə çalışsan:


var acc = new BankAccount("Lena", 1000m);
acc.Balance = -700m; // Səhv! set private-dir.

Və ya belə:


acc.Owner = "Haker"; // Kompilyasiya səhvi, set yoxdur

— heç nə alınmayacaq. Yalnız konstruktor və ya method-larla dəyişmək olar.

Səhv: "gözəllik üçün" property-lər

Çoxları belə yazır:


public int Age { get; set; }

Halbuki yaş yalnız IncreaseAge method-u ilə (məsələn, 1 yanvar) dəyişməlidir, birbaşa yox.

7. Vizual xatırlatma: necə olmaz və necə olmalıdır

graph TD
    A[Public Fields] -->|İstənilən kod| D[Nəzarətsiz vəziyyət]
    B[Private Fields + Public Methods] -->|Düzgün təyin olunmuş| E[Nəzarətli vəziyyət]
    F[Public Setters] -->|Hər kəs dəyişə bilər| D
    G[Private Setters] -->|Yalnız class| E
Yanaşma Vəziyyət qorunur? Validasiya etmək olar? Asan genişlənir?
Public field-lar ❌ ❌ ❌
Property-lər (get/set public) ❌ Qismən Bəli, amma təhlükəli
Private field-lar + property ilə set private ✅ ✅ ✅

8. İnkapsulyasiya ilə işləmək üçün stil məsləhətləri

  • Yalnız class istifadəçisinə həqiqətən lazım olanı açıq et.
  • Obyektə daxil olan datanı həmişə yoxla (validate et).
  • Artıqlığa qaçma: əgər property xaricdən dəyişməməlidirsə — set-i private et.
  • Qeyri-standart məntiq üçün — həmişə method istifadə et, birbaşa çıxış yox.
  • Çox istəsən belə — test üçün public field etmə.
  • Hətta public oxumaq üçün belə, birbaşa field yox, property istifadə et — sonra asan dəyişmək olur.
2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
Giriş səviyyələri və inkapsulyasiya ilə bağlı səhvlər
Giriş səviyyələri və inkapsulyasiya ilə bağlı səhvlər
2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
İnkapsulyasiyanın həyata keçirilməsi və sinifin vəziyyətinin qorunması
İnkapsulyasiyanın həyata keçirilməsi və sinifin vəziyyətinin qorunması
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION