کپسوله سازی (Encapsulation)
کپسوله سازی (Encapsulation) به عنوان فرآیند محصور کردن یک یا چند مورد در یک بسته فیزیکی یا منطقی تعریف می شود. کپسوله سازی در برنامه نویسی شی گرا، از دسترسی به جزئیات پیاده سازی جلوگیری می کند. انتزاع (Abstraction) و کپسوله سازی (Encapsulation) در برنامه نویسی شی گرا به یکدیگر مرتبط هستند. انتزاع اطلاعات مرتبط را قابل مشاهده می کند و کپسوله سازی برنامه نویس را قادر می سازد تا سطح مطلوب انتزاع را پیاده سازی کند.
در زبان های برنامه نویسی شی گرا، کپسوله سازی یکی از ویژگی های کلیدی زبان است. Encapsulation فرآیند کپسوله سازی داده ها و توابع در یک واحد (به نام کلاس) است. کپسوله سازی در زبان سی شارپ، به توانایی یک شیء برای پنهان کردن داده ها و رفتارهایی اشاره دارد که برای کاربر آن ضروری نیست. کپسوله سازی گروهی از properties، متدها و سایر اعضا را قادر می سازد تا به عنوان یک واحد یا شی واحد در نظر گرفته شوند.
چرا به کپسوله سازی نیاز داریم؟
مزایای Encapsulation به شرح زیر است:
1- حفاظت از داده ها در برابر خرابی تصادفی
2- مشخص کردن قابلیت دسترسی هر یک از اعضای یک کلاس به کد خارج از کلاس
3- انعطاف پذیری و قابلیت گسترش کد و کاهش پیچیدگی
4- متصل بودن کمتر اشیا و در نتیجه بهبود قابلیت نگهداری کد
Encapsulation برای محدود کردن دسترسی به اعضای یک کلاس استفاده می شود تا از دستکاری اشیاء توسط کاربر کلاس به روش هایی که طراح در نظر گرفته نشده است جلوگیری کند. در حالی که کپسوله سازی پیاده سازی داخلی عملکردهای کلاس را بدون تأثیر بر عملکرد کلی سیستم پنهان می کند، به کلاس اجازه می دهد تا یک درخواست برای عملکرد را ارائه دهد و ساختار داخلی خود (داده ها یا متدها) را متناسب با نیازهای متغیر اضافه یا اصلاح کند.
نیاز به کپسوله سازی، محافظت یا جلوگیری از خرابی تصادفی کد (داده ها) به دلیل خطاهای کوچکی است که همه ما مستعد انجام آن ها هستیم. در برنامه نویسی شی گرا، داده ها به عنوان یک عنصر حیاتی در توسعه برنامه تلقی می شوند و داده ها نزدیک به توابعی که بر روی آن کار می کنند بسته بندی می شوند و از آن در برابر تغییرات تصادفی توابع خارجی محافظت می کنند.
همانطور که قبلاً اشاره شد کپسوله سازی راهی برای محافظت از داده ها در برابر خرابی تصادفی فراهم می کند. به جای تعریف داده ها به صورت عمومی، می توانیم آن فیلدها را به عنوان خصوصی اعلام کنیم. داده های خصوصی به دو صورت غیر مستقیم دستکاری می شوند. اجازه دهید چند برنامه نمونه در سی شارپ برای نشان دادن کپسولاسیون با این دو روش ببینیم. روش اول استفاده از یک جفت روش متداول accessor و mutator است. یکی دیگر از روش ها استفاده از یک ویژگی نامگذاری شده (named property) است. هر روشی که باشد، هدف ما استفاده از داده ها بدون آسیب یا تغییر است.
کپسوله سازی با استفاده از accessors و mutators
در مثال زیر به کلاس Department توجه کنید. برای دستکاری داده ها در آن کلاس (String departname) یک Accessor (متد get) و mutator (متد set) تعریف می کنیم.
مانند روش فوق، ما می توانیم از داده های خصوصی در برابر دنیای خارج محافظت کنیم. در اینجا از دو روش مجزا برای تخصیص و دریافت داده های مورد نیاز استفاده می کنیم.
در مثال بالا، ما نمی توانیم به داده خصوصی department از طریق یک نمونه شیء دسترسی پیدا کنیم. ما داده ها را فقط با استفاده از دو متد فوق الذکر دستکاری می کنیم.
کپسوله سازی با استفاده از properties
Properties یک ویژگی زبانی جدید است که توسط زبان برنامه نویسی سی شارپ (c#) معرفی شده است. فقط چند زبان از این ویژگی پشتیبانی می کنند. Properties در سی شارپ به محافظت از یک فیلد در کلاس با خواندن و نوشتن در آن کمک می کند. روش اول که در بخش قبل توضیح داده شد به خودی خود خوب است اما Encapsulation با properties بسیار راحت تر انجام می شود. به مثال زیر توجه کنید.
در مثال بالا Encapsulation با استفاده از properties نشان داده شده است. property دارای دو accessor با نام های get و set می باشد. get accessor مقدار فیلد property را برمی گرداند. set accessor مقدار فیلد property را با محتوای "value" ست می کند.
کپسوله سازی با استفاده از تعیین کننده های سطح دسترسی (access specifiers) پیاده سازی می شود. access specifiers ، محدوده و قابل مشاهده بودن یک عضو کلاس را تعریف می کند. زبان برنامه نویسی سی شارپ از access specifiers های زیر پشتیبانی می کند که در ادامه شرح داده می شوند:
1- Public
2-Private
3- Protected
4- Internal
5- Protected internal
6- private protected
سطح دسترسی Public
تعیین کننده سطح دسترسی عمومی (public access specifier) به یک کلاس اجازه می دهد تا متغیرهای عضو و توابع عضو خود را در معرض دید و دسترسی سایر توابع و اشیاء قرار دهد. هر عضو از نوع public از خارج از کلاس قابل دسترسی است. مثال زیر این موضوع را نشان می دهد.
خروجی قطعه کد بالا در ادامه نشان داده شده است.
در مثال بالا، متغیرهای length و width عمومی اعلام شده اند، بنابراین می توان از طریق تابع ()Main با استفاده از نمونه ای از کلاس Rectangle به نام r به آنها دسترسی داشت.
تابع عضو ()Display و ()GetArea نیز می توانند مستقیماً بدون استفاده از هیچ نمونه ای از کلاس به این متغیرها دسترسی داشته باشند.
توابع عضو ()Display نیز عمومی اعلام می شود، بنابراین می توان از Main() با استفاده از نمونه ای از کلاس Rectangle به نام r نیز به آن دسترسی داشت.
سطح دسترسی Private
تعیین کننده سطح دسترسی خصوصی (private access specifier) به یک کلاس اجازه می دهد تا متغیرهای عضو و توابع عضو خود را از توابع و اشیاء دیگر پنهان کند. فقط توابع یک کلاس می توانند به اعضای خصوصی آن دسترسی داشته باشند. حتی یک نمونه از یک کلاس نمی تواند به اعضای خصوصی خود دسترسی داشته باشد. مثال زیر این موضوع را نشان می دهد.
خروجی قطعه کد بالا در ادامه نشان داده شده است.
در مثال بالا، متغیرهای length و width خصوصی اعلام شده اند، بنابراین نمی توان از تابع ()Main به آنها دسترسی داشت. توابع عضو ()AcceptDetails و ()Display می توانند به این متغیرها دسترسی داشته باشند. از آنجایی که توابع عضو ()AcceptDetails و ()Display عمومی اعلام می شوند، می توان از ()Main با استفاده از نمونه ای از کلاس Rectangle به نام r به آنها دسترسی داشت.
سطح دسترسی Protected
تعیین کننده سطح دسترسی محافظت شده (protected access specifier) به یک کلاس فرزند (child class) اجازه می دهد تا به متغیرهای عضو و توابع عضو کلاس پایه خود (base class) دسترسی داشته باشد.
خروجی قطعه کد بالا در ادامه نشان داده شده است.
سطح دسترسی Internal
تعیین کننده سطح دسترسی داخلی (protected access specifier) به یک کلاس اجازه می دهد تا متغیرهای عضو و توابع عضو خود را در معرض دید و دسترسی سایر توابع و اشیاء در اسمبلی فعلی قرار دهد. به عبارت دیگر، هر عضو با تعیین کننده سطح دسترسی داخلی را می توان از طریق هر کلاس یا متدی که در برنامه تعریف شده است، دسترسی داشت. قطعه کد زیر این موضوع را نشان می دهد.
خروجی قطعه کد بالا در ادامه نشان داده شده است.
در مثال قبل، توجه کنید که برای تابع عضو GetArea() هیچ تعیین کننده سطح دسترسی مشخص نشده است. اگر به هیچ کدام اشاره نکنیم، مشخص کننده دسترسی پیش فرض یک عضو کلاس خصوصی چه خواهد بود.
سطح دسترسی Protected Internal
تعیین کننده سطح دسترسی داخلی محافظت شده (protected internal access specifier) به یک کلاس اجازه می دهد تا متغیرهای عضو و توابع عضو خود را از سایر اشیاء و توابع کلاس پنهان کند، به جز کلاس فرزند در همان برنامه. این مفهوم در هنگام پیاده سازی وراثت نیز استفاده می شود. مثال زیر و خروجی آن را ببینید.
خروجی قطعه کد بالا در ادامه نشان داده شده است.
سطح دسترسی محافظت شده خصوصی private protected
در این مورد دسترسی به کلاس و انواع مشتق شده آن که در اسمبلی جاری موجود هستند، داده می شود. این نوع در سی شارپ نسخه 7.2 به بعد معتبر است. در مثال نشان داده شده در زیر، از آنجایی که تعیین کننده سطح دسترسی برای مقدار عضو محافظت خصوصی (private protected) است، اکنون در کلاس مشتق شده یاParent یعنی Child قابل دسترسی است. هر کلاس مشتق شده ای که ممکن است در اسمبلی دیگری وجود داشته باشد، نمی تواند به این اعضای محافظت شده خصوصی دسترسی داشته باشد.
خروجی قطعه کد بالا در ادامه نشان داده شده است.