آموزش گام به گام #C (جلسه نوزدهم: کپسوله‌سازی)
1398/01/24 15:09 , میلاد صاحب نظر

آموزش گام به گام #C (جلسه نوزدهم: کپسوله‌سازی)

کپسوله‌سازی یکی از اصول سه‌گانه برنامه‌نویسی شیءگرا است که در درجه اول باعث افزایش ضریب امنیت برنامه شما می‌شود و در درجه دوم خوانایی و قابلیت رسیدگی و تغییر کد را تسهیل می‌کند. با ما همراه باشید!

جلسه اول: آغاز کار با #C جلسه ششم: namespaceها جلسه یازدهم: اندیس گذار یا indexerها جلسه شانزدهم: استفاده از اتریبیوت‌ها جلسه بیست و یکم: متدهای بی‌نام یا anonymous
جلسه دوم: عملگرها، نوع‌ها و متغیرها جلسه هفتم: مقدمه‌ای بر کلاس‌های #C جلسه دوازدهم: ساختار یا structها جلسه هفدهم: enumها جلسه بیست و دوم: موضوعاتی در مورد نوع در #C
جلسه سوم: عبارات کنترلی - گزینشی جلسه هشتم: وراثت کلاس در #C جلسه سیزدهم: واسط یا interfaceها جلسه هجدهم: عملگرهای overloading جلسه بیست و سوم: کار با نوع‌های nullable
جلسه چهارم: عبارات کنترلی - حلقه‌ها جلسه نهم: چندریختی جلسه چهاردهم: مقدمه‌ای بر delegateها و رویدادها جلسه نوزدهم: کپسوله‌سازی  
جلسه پنجم: متدها جلسه دهم: ویژگی یا propertyها جلسه پانزدهم: مقدمه‌ای بر کنترل خطا یا exception جلسه بیستم: مقدمه‌ای بر generic collectionها  

در جلسات قبلی در مورد دو اصل مهم برنامه‌نویسی شیءگرا (یعنی ارث‌بری و چند ریختی) آموختید. حالا که با Syntax یا نحوه کد نویسی #C آشنا شدید، به شما نشان خواهم داد که یک اصل شیءگرایی دیگر (یعنی کپسوله‌سازی) چگونه در #C انجام می‌شود.

این جلسه در مورد کپسوله‌سازی است و اهداف ما به شرح زیر هستند:

  • درک اصل شیءگرایی کپسوله‌سازی
  • آشنایی با modifierهای موجود برای اعضای نوع
  • محافظت از حالت(State) شیء از طریق Propertyها
  • کنترل دسترسی به متدها
  • آموختن چگونگی تغییر یا اصلاح نوع‌ها برای کپسوله‌سازی اسمبلی

کپسوله‌سازی چیست و چه نفعی برای ما دارد؟

در برنامه‌نویسی شیءگرا، شما اشیائی ایجاد می‌کنید که دارای حالت(State) و رفتار(behavior) هستند. حالت یک شیء در واقع همان داده یا اطلاعاتی است که درون شیء می‌باشد. برای مثال، اگر شیئی به نام BankAccount داشته باشید، حالت آن می‌تواند Amount و CustomerName باشد.

رفتار در یک شیء گاهی توسط متدها نمایش داده می‌شود. برای مثال، رفتار شیء BankAccount می‌تواند متدهای Credit، Debit و GetAmount باشند. این‌هایی که گفته شد به نظر تعریف شیء هستند، این‌طور نیست؟ واقعاً هم همین‌طور است، اما همچنین باید چگونگی استفاده از این شیء را نیز در نظر بگیرید.

وقتی یک شیء طراحی می‌کنید، باید در مورد چگونگی استفاده آن توسط دیگران فکر کنید. در بهترین وضعیت، هر برنامه‌ای که از شیء استفاده می‌کند به خوبی طراحی می‌شود و دیگر لازم نیست که در آینده کد تغییر کند.

ولی به هر حال، واقعیت این است که برنامه‌ها گاهی تغییر می‌کنند و در یک محیط تیمی، هر از گاهی تعداد زیادی از افراد به یک کد می‌رسند. از این رو، در عین حال که تصور خوبی از اینکه شیء باید چگونه مورد استفاده قرار گیرد دارید، بسیار مفید است که این مسئله را نیز در ذهن داشته باشید که چه اشتباهی ممکن است رخ دهد.

در مثال شیء BankAccount، حالتی را آزمایش کنید که در آن کد خارج از شیء شما بتواند به یک فیلد اعشاری Amount یا یک فیلد رشته CustomerName دسترسی یابد. در لحظه‌ای که کد نوشته می‌شود، همه چیز به درستی عمل می‌کند.

به هر حال، در مراحل بعدی چرخه توسعه، متوجه می‌شوید که شیء BankAccount می‌بایست یک CustomerID از نوع int را پیگیری می‌کرد نه یک CustomerName از جنس string. چون شما نمی‌خواهید روابط بین اطلاعات را تکرار کنید (یا دلیل قابل‌قبول دیگری برای تغییر تعریف یک حالت داخلی).

چنین تغییراتی باعث بروز یک تأثیر موجی در کد شما می‌شوند، چون کد شما به گونه‌ای نوشته شده بود که از طراحی اولیه کلاس BankAccount استفاده کند (یعنی با حالت فیلد CustomerName از جنس string) و الان باید کدی که در کل برنامه شما به آن حالت دسترسی داشته را تغییر دهید.

اصل شیءگرایی کپسوله‌سازی به جلوگیری از چنین مشکلاتی کمک می‌کند و از طریق اعضای نوع (مانند متدها، Propertyها و شاخص گذارها یا indexerها) برای شما امکان مخفی کردن حالت داخلی و دسترسی انتزاعی (abstract)به آن را مهیا می‌کند.

کپسوله‌سازی به شما کمک می‌کند تا وابستگی (coupling) بین اشیاء را کاهش و قابلیت رسیدگی و نگهداری کدتان را بهبود دهید.

تعیین سطح دسترسی(Access midifier) عضو نوع

تعیین سطح دسترسی(Access modifier) به شما اجازه می‌دهد میزان در دسترس بودن کد خود را در خارج از یک نوع یا اسمبلی مشخص کنید. تعیین کننده‌های سطح دسترسی را می‌توان یا برای نوع‌ها و یا برای اعضای نوع به کار برد.

در جلسات بعدی راجع به تعیین کننده‌های سطح دسترسی صحبت خواهیم کرد و متوجه خواهید شد که modifierها می‌توانند برای نوع‌ها به کار روند. در این جلسه فقط در مورد modifierهایی صحبت خواهیم کرد که برای اعضای نوع به کار می‌روند و همچنین خواهیم گفت که چگونه بر میزان دسترسی آن‌ها تأثیر می‌گذارند.

در کل، شما باید حالت داخلی شیء خود را از دسترسی مستقیم توسط کدهای خارج از شیء پنهان کنید. سپس باید اعضای دیگر (مانند متدها و propertyها) که آن حالت را پوشش می‌دهند پیاده‌سازی کنید.

این کار باعث می‌شود که هر موقع خواستید، بتوانید پیاده‌سازی داخلی حالت را تغییر دهید، در عین حال اعضای مخفی کننده یا پوشاننده حالت می‌توانند یک نماینده از حالت که تغییر نمی‌کند، بازگردانند.

این بدان معنا است که کد خارج از شیء از طریق اعضایی که حالت را مخفی می‌کنند به شیء شما دسترسی می‌یابند و تضمین می‌شود که نوع اطلاعات استخراج شده نامتناقض باقی بماند. علاوه بر این، چون کد خارجی به حالت داخلی شیء شما دسترسی ندارد، پس نمی‌تواند در آن حالت تناقض ایجاد کند و روش عملکرد شیء شما را تغییر دهد.

اولین مرحله در کپسوله‌سازی شیء، این است که مشخص کنیم آن کد خارج از شیء چه نوع دسترسی‌ای باید به اعضای نوع شما داشته باشد. این کار با استفاده از تعیین کننده‌های سطح دسترسی (access modifierها) انجام می‌شود.

نوع دسترسی اعطا شده از "هیچ دسترسی خارجی" تا "دسترسی عمومی" و دسترسی فقط چند متغیر متفاوت است. جدول ۱-۱۹ لیستی از تمام تعیین کننده‌های سطح دسترسی عضو نوع را نمایش داده و همچنین معنای آن‌ها را توضیح می‌دهد.

جدول ۱-۱۹. تعیین کننده‌های سطح دسترسی عضو نوع، کدی را که به یک عضو نوع خاص دسترسی دارد را کنترل می‌کنند.

Access Modifier

توضیح (چه کسی می‌تواند دسترسی داشته باشد)

private

فقط اعضای داخل همان نوع. (حالت پیش‌فرض برای اعضای نوع)

protected

فقط نوع‌ها یا اعضای مشتق شده از همان نوع.

internal

فقط کد داخل همان اسمبلی. همچنین می‌تواند کد خارج از شیء نیز باشد، به شرطی که در یک اسمبلی قرار داشته باشند. (حالت پیش‌فرض برای نوع‌ها)

protected internal

یا کد مشتق شده از نوع یا کد داخل اسمبلی یکسان. ترکیب protected OR internal

public

هر کدی. هیچ محدودیت ارث‌بری، نوع خارجی یا اسمبلی خارجی وجود ندارد.

همان‌طور که در جلسات پیش آموختید، نوع‌ها حاوی چند عضو نوع می‌باشند، که برخی از آن‌ها عبارت‌اند از سازنده‌ها (constructorها)، Propertyها، شاخص گذارها (indexerها)، متدها و غیره.

به جای اینکه یک لیست خسته کننده از همه جایگزین‌های تعیین‌کننده سطح دسترسی که می‌توانید برای این اعضا به کار ببرید، از یک روش بهتر استفاده می‌کنیم و یک زیرمجموعه از تعیین‌کننده‌های سطح دسترسی مورد استفاده برای propertyها و متدها را توضیح می‌دهیم.

اعطای دسترسی public به اعضای نوع

قبلاً نحوه استفاده از دسترسی public را در جلسات قبل مشاهده کردید. هر موقع برای یک عضو نوع از یک تعیین‌کننده سطح دسترسی public استفاده می‌شود، کد فراخوانی می‌تواند به عضو نوع دسترسی داشته باشد.

اگر برای عضو نوع خود دسترسی public ایجاد کردید، در واقع به همه اجازه می‌دهید که از آن استفاده کنند. لیست ۱-۱۹ مثالی از استفاده تعیین‌کننده سطح دسترسی برای یک متد را نشان می‌دهد.

لیست ۱-۱۹. تعریف یک متد با یک تعیین کننده سطح دسترسی public: BankAccountPublic.cs

متد ()GetAmount در لیست ۱-۱۹ public است. یعنی اینکه این متد می‌تواند توسط هر کد موجود در خارج از این کلاس فراخوانی شود. حالا، می‌توانید کد زیر را در هر جایی از برنامه خود بنویسید و از این متد استفاده کنید:

تنها کاری که باید انجام دهید (همان‌طور که در کد بالا می‌بینید) ایجاد یک نمونه یا instance از کلاس است، که این instance باید شامل متد باشد و سپس متد از طریق آن instance فراخوانی شود. چون این متد public است، هیچ مشکلی نخواهید داشت.

به یاد داشته باشید که دسترسی پیش‌فرض برای یک عضو نوع، دسترسی private است که در بخش بعدی راجع به آن صحبت خواهیم کرد. این بدان معنا است که اگر modifier یا نشانگر public را فراموش کردید، و اصلاً از هیچ modifier دیگری استفاده نکردید، یک ارور کامپایلر دریافت خواهید کرد.

مخفی کردن اعضای نوع با دسترسی private

یک عضو نوع private عضوی است که می‌توان فقط از طریق اعضای داخل همان نوع به آن دسترسی یافت. برای مثال، اگر کلاس BankAccount دارای یک عضو private‌باشد، فقط اعضای دیگر داخل کلاس BankAccount می‌توانند به آن عضو دسترسی داشته یا آن را فراخوانی کنند.

اگرچه دسترسی پیش‌فرض برای اعضای نوع دسترسی private است، اما همیشه ترجیح بر این است که قصد و هدف خود را در هنگام تعریف اعضای نوع به صورت  کتبی بنویسید و از تعیین‌کننده‌های سطح دسترسی استفاده کنید، نه اینکه به پیش‌فرض‌ها اتکا کنید.

این کار باعث خواناتر شدن کد می‌شود و هدف و قصد واقعی شما برای توسعه‌دهندگان دیگری که ممکن است کد شما را بخوانند نیز روشن خواهد شد. لیست ۲-۱۹ چگونگی استفاده از تعیین‌کننده سطح دسترسی Private را نشان داده و مثالی ارائه می‌دهد که بیان می‌کند چرا باید از آن استفاده کرد.

لیست ۲-۱۹. تعریف یک فیلد private: BankAccountPrivate.cs

کپسوله‌سازی حالت نوع با استفاده از Propertyها یک روش مرسوم است. در واقع، بهتر است همیشه حالت خود را در یک Property پنهان کنید. در لیست ۲-۱۹، مشاهده‌ می‌کنید که نام مشتری چطور در فیلد m_name نگهداری، اما با استفاده از Property به نام CustomerName پنهان (کپسوله‌سازی) شده است.

چون m_name به صورت private تعریف شده است، کد خارج از کلاس BankAccountPrivate نمی‌تواند مستقیماً به آن دسترسی یابد. در عوض، برای دسترسی یافتن باید از property به نام CustomerName که دارای سطح دسترسی public است، استفاده کند.

حالا می‌توانید پیاده‌سازی m_name را به هر روشی که می‌خواهید تغییر دهید.

برای مثال، اگر بخواهید یک ID از نوع int وجود داشته باشد و property به نام CustomerName جستجویی برای یافتن نام انجام دهد یا اگر بخواهید مقادیر نام و نام خانوادگی (که property به نام CustomerName روی آن‌ها تمرکز می‌کند) را به دست آورید چه کار می‌کنید؟

در هنگام بررسی و رسیدگی به کد، اتفاقات خیلی زیادی برای کد شما می‌افتند که باعث تغییر پیاده‌سازی می‌شوند. نکته این است که اعضای Private امکان تغییر دادن پیاده‌سازی بدون محدود کردن آن یا به وجود آمدن تأثیرات موجی در کد (که اگر کد خارج از شیء به اعضای نوع شما دسترسی داشت ممکن بود اتفاق بیفتند) را فراهم می‌کنند.

تعیین‌کننده‌های سطح دسترسی private و public دقیقه دو نوع دسترسی متفاوت هستند، یا از دسترسی همه کدهای خارج از شیء به اعضای داخل شیء جلوگیری می‌کنند یا برعکس. بقیه تعیین‌کننده‌های سطح دسترسی چیزی بین این دو می‌باشند، به خصوص تعیین‌کننده protected که در بخش بعدی توضیح داده شده است.

دسترسی برای نوع‌های مشتق شده با استفاده از تعیین‌کننده سطح دسترسی protected

تعیین‌کننده سطح دسترسی protected به نوعی شبیه به هر دو تعیین‌کننده‌های سطح دسترسی private و  public عمل می‌کند. همانند Private، فقط امکان دسترسی به اعضای درون همان نوع را فراهم می‌کند، به استثنای اینکه فقط برای نوع‌های مشتق شده، همانند public عمل می‌کند.

یا به بیان دیگر، اعضای نوع protected فقط توسط اعضای داخل همان نوع یا نوع‌های مشتق شده قابل دسترسی هستند.

برگردیم به سراغ مثال BankAccount خودمان. اگر لازم شد کدی فراخوانی کنید که یک حساب بانکی را ببندد چه می‌کنید؟ علاوه بر این، اگر انواع مختلفی از حساب‌های بانکی وجود داشته باشند چطور؟

هر کدام از این انواع حساب‌های بانکی مختلف دارای منطق خاص خودشان برای بسته شدن می‌باشند، اما فرآیند پایه و اولیه برای همه انواع حساب‌ها یکسان می‌باشد. اگر فکر می‌کنید این عملکرد چیزی شبیه به عملکرد چند ریختی است، پس در مسیر درستی قرار دارید.

در جلسه نهم،  در مورد چند ریختی صحبت کردیم و گفتیم که چگونه به ما اجازه می‌دهد که با چندین کلاس به صورت مشابه رفتار کنیم. شاید بد نباشد که برای درک بهتر مثال بعدی، جلسه نهم را مرور کنید.

در مثال بستن حساب بانکی، چندین عمل باید انجام شوند (مانند محاسبه سودی که باید پرداخت شود، اعمال جریمه برای دیرکرد پرداخت وام و حذف کردن حساب از پایگاه داده). از طرفی، نباید کدی برای فراخوانی متدهای کلاس BankAccount بنویسید، مگر اینکه همه متدها به ترتیب درست فراخوانی شوند.

برای مثال، اگر کدی بنویسید که متدی برای حذف حساب از پایگاه داده فراخوانی کند، اما سود و جریمه‌ها را محاسبه نکند چه اتفاقی می‌افتد؟ یک نفر پولش را از دست می‌دهد. همچنین، اگر کد فراخوانی ابتدا حساب را حذف کند و بعد متدهای دیگر اجرا شوند، با ارور مواجه خواهید شد چون اطلاعات حساب دیگر در دسترس نیستند.

از این رو، باید این وضعیت را کنترل کنید و لیست ۳-۱۹ چگونگی انجام آن را نمایش می‌دهد.

لیست ۳-۱۹. تعریف متدهای protectted: BankAccountProtected.cs

مهم‌ترین بخش لیست ۳-۱۹، متد CloseAccount است که public بوده و بقیه متدها protected می‌باشند. هر کد فراخوانی می‌تواند از BankAccountProtected نمونه‌سازی کند، اما فقط می‌تواند متد CloseAccount را فراخوانی کند.

این امر باعث می‌شود از حساب در مقابل شخصی که رفتار شیء شما را به صورت غیر مجاز فراخوانی می‌کند، محافظت شود. در نتیجه منطق کسب و کار شما قوی و هوشمندانه است.

در پایان این جلسه، مثالی از چگونگی فراخوانی کد در لیست ۳-۱۹ مشاهده خواهید کرد. فعلاً، ضروری است که درک کنید بخش‌های دیگر لیست چگونه عمل می‌کنند.

اگر هدف شما این است که کلاس BankAccountProtected فقط روی اعضای خودش عملیات انجام دهد، پس باید متدهای protected را به private تغییر دهید. به هر حال، این کد از یک framework پشتیبانی می‌کند که در آن می‌توانید انواع مختلف حساب (مانند پس‌انداز، چکی و غیره) داشته باشید.

می‌توانید در آینده انواع حساب جدیدی اضافه کنید، چون کلاس BankAcoountProtected به گونه‌ای طراحی شده است که با متدهای مجازی protected از آن‌ها پشتیبانی کند. لیست ۴-۱۹ و ۵-۱۹ کلاس‌های SavingsAccount و CheckingAccount که از کلاس BankAccountProtected مشتق گرفته شده‌اند را نمایش می‌دهند.

لیست ۴-۱۹. کلاس SavingsAccount مشتق شده از اعضای protected کلاس پایه خودش استفاده می‌کند: SavingsAccount.cs

توجه کنید که SavingsAccount چگونه از BankAccountProtected مشتق گرفته شده است. می‌توان توسط هر کدام از اعضای protected از کلاس BankAccountProtected (که کلاس پایه می‌باشد)به SavingsAccount دسترسی داشت.

کد بالا این حقیقت را از طریق فراخوانی base.DeleteAccountFromDB در متد DeleteAccountFromDB نشان داده است. اگر بخش ارث‌بری لیست ۴-۱۹ کمی گیج کننده است، می‌توانید جلسه هشتم: ارث‌بری در کلاس‌ها را مرور کنید تا بهتر کد بالا را درک کنید.

هر متد از SavingsAccount همچنین دارای تعیین‌کننده سطح دسترسی protected نیز می‌باشد، که به زبان ساده یعنی اینکه کلاس‌های مشتق شده از SavingsAccount، با استفاده از تعیین‌کننده سطح دسترسی protected، می‌توانند به اعضای SavingsAccount دسترسی یابند.

همین وضعیت در مورد کلاس CheckingAccount وجود دارد که در لیست ۵-۱۹ نمایش داده شده است.

لیست ۵-۱۹. کلاس CheckingAccount مشتق شده، از اعضای Protected کلاس پایه‌اش استفاده می‌کند: CheckingAccount.cs

کلاس CheckingAccount در لیست ۵-۱۹ دقیقه مشابه با کلاس SavingsAccount در لیست ۴-۱۹ پیاده‌سازی شده است. اگر خودتان این کدها را بنویسید، متوجه خواهید شد که تفاوت بین آن‌ها این است که متدهای هر کلاس دارای پیاده‌سازی‌های منحصر به فرد هستند.

برای مثال، قوانین کسب و کار مرتبط با محاسبه سود نهایی متفاوت است و این امر بستگی به این دارد که نوع حساب Checking‌یا Savings باشد.

به فراخوانی به سمت متد کلاس پایه در متد DeleteAccountFromDB در کلاس CheckingAccount دقت کنید. درست همانند SavingsAccount، CheckingAccount نیز به متد protected از کلاس BankAccountProtected  دسترسی دارد، چون یک کلاس مشتق گرفته شده است.

این یک الگوی مرسوم در چند ریختی است، چون کلاس‌های مشتق شده گاهی دارای مسئولیت فراخوانی متدهای کلاس پایه مجازی می‌باشند تا اطمینان حاصل شود که عملکرد بحرانی فرصتی برای اجرا شدن داشته باشد. شاید بد نباشد سند متد را مطالعه کنید تا بفهمید آیا این کار ضروری است یا خیر.

بدون یک تعیین‌کننده سطح دسترسی protected، تنها گزینه شما این است که متد کلاس پایه را public کنید، که همان‌طور که قبلاً توضیح داده شد، این کار خطرناک است.

برای استفاده از کد موجود در لیست ۳-۱۹، ۴-۱۹ و ۵-۱۹، می‌توانید کد زیر را پیاده‌سازی کنید:

چون هم SavingsAccount و هم CheckingAccount از BankAccountProtected‌ مشتق گرفته می‌شوند، می‌توانید آن‌ها را به آرایه bankAccts اختصاص دهید.

آن‌ها هر دو متدهای مجازی protected از کلاس BankAccountProtected را override یا بازنویسی می‌کنند، بنابراین این متدهای SavingsAccount و CheckingAccount هستند که در هنگام اجرا شدن CloseAccount از کلاس BankAccountProtected فراخوانی می‌شوند.

به یاد داشته باشید که تنها دلیلی که متدهای SavingsAccount و CheckingAccount می‌توانند متدهای کلاس پایه مجازی خود را فراخوانی کنند (همان‌طور که در مثال DeleteAccountFromDB مشاهده کردید)، این است که متدهای کلاس پایه مجازی با تعیین‌کننده سطح دسترسی protected نشانه‌گذاری شده‌اند.

یک صحبت کوتاه در مورد تعیین‌کننده‌های سطح دسترسی internal و protected internal

در عمل، اکثر کدهایی که می‌نویسید شامل تعیین‌کننده‌های سطح دسترسی public، Private و protected خواهند بود. به هر حال، دو تعیین‌کننده سطح دسترسی دیگر نیز وجود دارند که می‌توانید از آن‌ها در برخی سناریو‌ها استفاده کنید: internal و protected internal.

هر موقع یک کتابخانه کلاس مجزا ایجاد کردید و نمی‌خواهید هیچ کد خارج از کتابخانه به کدهای دارای سطح دسترسی internal دسترسی داشته باشند، از internal استفاده می‌شود. Protected internal ترکیبی از دو تعیین‌کننده سطح دسترسی با همین اسامی می‌باشد. این بدان معنا است که یا protected است یا internal.

تعیین‌کننده‌های سطح دسترسی برای نوع‌ها

تا اینجا، مبحث تعیین‌کننده‌های سطح دسترسی فقط برای نوع‌های عضو به کار رفته است. به هر حال، قوانین برای خود نوع‌ها متفاوت است. وقتی راجع به نوع‌ها صحبت می‌کنیم، در واقع به تمام نوع‌های #C اشاره می‌کنیم (به خصوص کلاس‌ها، Structها، واسط‌ها، delegateها و enumها).

نوع‌های تو در تو (مانند کلاس)، درون دامنه کلاس تعریف می‌شوند و به عنوان اعضای نوع شناسایی می‌شوند و از همان قوانین دسترسی مشابه با دیگر اعضای نوع پیروی می‌کنند.

نوع‌ها می‌توانند دارای دو تعیین‌کننده سطح دسترسی باشند: public‌ یا internal. اگر یک تعیین‌کننده سطح دسترسی مشخص نکنید، به صورت پیش‌فرض internal در نظر گرفته می‌شود.

اگر همه کلاس‌های مورد استفاده در این جلسه را بررسی کنید، مشاهده خواهید کرد که همه internal هستند، چون هیچ تعیین‌کننده سطح دسترسی ندارند. می‌توانید به وضوح internal را بیان کنید، مثل کد زیر:

شاید کلاس InternalInterestCalculator که در بالا نشان داده شده است، دارای قوانین کسب و کار خاصی باشد که شما نخواهید کدهای دیگر از آن‌ها استفاده کنند. حالا، این کلاس در یک کتابخانه کلاس خاص خودش قرار دارد و فقط می‌توان توسط کدهای دیگر درون همان کتابخانه کلاس (DLL) به آن دسترسی داشت.

نکته: به طور دقیق‌تر، Internal یعنی اینکه فقط کد موجود در همان اسمبلی می‌تواند به کد نشانه‌گذاری شده با Internal دسترسی داشته باشد. به هر حال، بحث در مورد تعریف یک اسمبلی خارج از دامنه مباحث این جلسه است، بنابراین فقط به بیان معنای لغوی آن بسنده می‌کنیم.

اگر یک کلاس درون یک کتابخانه کلاس تعریف کنید و بخواهید کدهای دیگر نیز از آن استفاده کنند، باید آن را با تعیین‌کننده سطح دسترسی public تعریف کنید.

کد زیر مثالی از به کار بردن تعیین‌کننده سطح دسترسی public برای یک نوع را نشان می‌دهد:

واضح است که یک حساب بانکی، چیزی است که لازم است از خارج از کتابخانه کلاس قابل دسترسی باشد.از این رو، منطقی است که یک تعیین‌کننده سطح دسترسی public به آن اختصاص دهیم. که در کلاس BankAccountExternal در بالا مشاهده می‌کنید.

نکته: در ویژوال استودیو وقتی یک کلاس جدید در یک کتابخانه کلاس ایجاد می‌کنید، یک مشکل پیش می‌آید. قالب پیش‌فرض شامل هیچ تعیین‌کننده سطح دسترسی نیست.

پس، وقتی سعی می‌کنید کدی بنویسید که از کلاس جدید در برنامه شما استفاده کند (که به کتابخانه کلاس رفرنس می‌کند)، یک ارور کامپایلر دریافت می‌کنید که می‌گوید: کلاس وجود ندارد. خب، شما می‌دانید که وجود دارد، چون همین الان آن را نوشتید و کد آن جلوش چشمتان است.

اگر متوجه نکته و راهنمایی که در اختیار شما قرار دادم شده باشید، پس متوجه این حقیقت هستید که قالب پیش‌فرض تعیین‌کننده سطح دسترسی را روی نوع قرار داده است. این امر باعث می‌شود تا سطح دسترسی پیش‌فرض کلاس internal باشد، که در نتیجه در خارج از این اسمبلی قابل استفاده و دسترسی نیست.

راه حل این مشکل این است که به کلاس یک تعیین‌کننده سطح دسترسی public بدهید، درست همانند کلاس BankAccountExternal در بالا.

خلاصه

کپسوله‌سازی یک اصل شیءگرایی برای پنهان کردن حالت و رفتار داخلی یک شیء است و باعث می‌شود کد شما خواناتر و بهتر شود. در #C، می‌توانید کپسوله‌سازی را با تعیین‌کننده‌ها سطح دسترسی مدیریت کنید.

برای مثال، تعیین‌کننده سطح دسترسی public به همه کدها اجازه دسترسی می‌دهد، اما تعیین‌کننده سطح دسترسی Private دسترسی را فقط به اعضای یک نوع محدود می‌کند. دیگر تعیین‌کننده‌های سطح دسترسی، دسترسی را در محدوده‌ای بین public و private قرار می‌دهند.

اگرچه برای اعضای نوع می‌توانید از هر تعیین‌کننده سطح دسترسی‌ای استفاده کنید، اما فقط دو تعیین‌کننده سطح دسترسی وجود دارند که می‌توانید برای نوع‌ها به کار ببرید و عبارت‌اند از public و Internal.

منبع: C#-Station

جلسه بعد                                                                جلسه قبل

 مطالب مرتبط

 مقدمه ای بر زبان برنامه نویسی #C و پلتفرم NET Framework.
7 دلیل منطقی برای آموختن #C
 طبقه بندی زبان های برنامه نویسی
به دست آوردن Exceptionها در #C و یافتن همه خطاها
 LINQ(زبان جستجوی یکپارچه)
برنامه نویسی شیءگرا چیست؟

از آخرین دوره های آموزشی و تخفیف ها مطلع شوید

با تکمیل فرم زیر ، از اخبار و اطلاعات به روز برنامه نویسی و تکنولوژی عقب نمانید

آخرین مطالب

آموزش جامع SQL Server (جلسه ۱۲)
آموزش جامع SQL Server (جلسه ۱۲)

دستور UPDATE در SQL Server برای تغییر داده‌های موجود در یک جدول، از دستور UPDATE به شکل زیر استفاده ...

آموزش جامع SQL Server (جلسه ۱۵)
آموزش جامع SQL Server (جلسه ۱۵)

دستور DROP TABLE در SQL Server گاهی، لازم است یک جدول که دیگر استفاده‌ای ندارد را حذف کنید. برای ...

آموزش جامع SQL Server (جلسه ۳۵: Window Functionها – بخش ۲)
آموزش جامع SQL Server (جلسه ۳۵: Window Functionها – بخش ۲)

بخش اول از آخرین مبحث دوره جامع آموزش SQL Server در جلسه قبلی بررسی شد. این مبحث که ...

آخرین دیدگاه ها

دیدگاه خود را درباره این پست بنویسید

فرم ارسال نظرات