اینترفیس در #C
شناسه پست: 2197
بازدید: 805

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

این مقاله، سرفصلی از دوره آموزشی زیر میباشد:

اگر می خواهید محتویات کامل این دوره را ببینید ، می توانید بر روی لینک سطح متوسطه #C کلیک کنید.

برای دانلود سورس، رو لینک سورس اینترفیسها در #C کلیک کنید.

ما این مقاله را به قسمتهای زیر تقسیم بندی میکنیم:

تعریف یک اینترفیس

برای تعریف یک اینترفیس، ما باید از کلمه interface استفاده کنیم. تعریف آن کاملا شبیه تعریف کلاس است با این تفاوت که از کلمه دیگری برای تعریف اینترفیس استفاده میکنیم. داخل اینترفیس، ما اعضا را بدون access modifier و بدنه پیاده سازی، مشخص میکنیم. بنابراین ما فقط اعضای درون اینترفیس را تعریف میکنیم. پیاده سازی آن، درون کلاسی که آن اینترفیس را پیاده سازی میکند انجام میشود:

پیاده سازی یک اینترفیس

برای پیاده سازی یک اینترفیس، ما یک کلاس یا ساختار را تعریف میکنیم که از آن اینترفیس ارث بری کند و تمام اعضای درون آن را پیاده سازی کند:

حالا اجازه بدید تا تمام این موارد را از طریق مثال زیر ببینیم:

همانطور که در مثال میبینیم، بعد از ارث بری کردن کلاسهایمان از یک اینترفیس، آنها موظف هستند که عضو ()WriteFile را پیاده سازی کنند در غیر اینصورت با خطای کامپایلر مواجه میشویم.

وقتیکه ما یک اینترفیس را پیاده سازی میکنیم، باید با رعایت قوانین زیر، از پیاده سازی متد اطمینان حاصل کنیم:

  • نام متدها و نوع های برگشتی آنها باید با نام و نوع برگشتی متد در اینترفیس دقیقا مطابقت داشته باشد.
  • تمام پارامترها باید دقیقا مطابقت داشته باشند.
  • تمام متدها باید در حین پیاده سازی، public باشند. این فقط در مورد پیاده سازی صریح اینترفیس صدق نمی کند (جلوتر در مورد آن صحبت خواهیم کرد).

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

ارجاع دادن کلاسها از طریق اینترفیسها

همانطور که ما میتوانیم یک آبجکت را با استفاده از یک متغیر کلاس رفرنس دهیم، میتوانیم یک آبجکت را با استفاده از یک متغیر اینترفیس نیز تعریف کنیم:

همانطور که میبینیم، تمام متدها از طریق آبجکت writer مورد دسترس هستند. اما حالا میخواهیم از یک آبجکت اینترفیس برای رفرنس دادن استفاده کنیم:

اگر ما از یک اینترفیس برای ایجاد یک آبجکت استفاده کنیم، در اینصورت فقط میتوانیم به اعضای تعریف شده درون آن اینترفیس دسترسی داشته باشیم.

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

اما پیاده سازی اینترفیس، مزیتهای بیشتر از این هم نیز دارد. یکی از آنها، جدا کردن آبجکت (object decoupling) است.

استفاده از یک اینترفیس برای جداسازی کلاسها

زمانیکه یک کلاس به یک کلاس دیگر وابسته است اصطلاحا آن کلاسها به یکدیگر وابستگی (coupled) دارند. این چیزی است که ما میخواهیم از آن اجتناب کنیم. زیرا اگر تغییری در کلاس A صورت گیرد و کلاس B به شدت به کلاس A وابسته باشد، آنگاه احتمال زیادی وجود دارد که ما مجبور به تغییر کلاس B نیز باشیم. یا حداقل، ما نمیتوانیم همچنان مطمئن باشیم که کلاس B هنوز به درستی کار میکند یا خیر. در نتیجه، ما میخواهیم کلاسهایمان کمتر به هم وابسته باشند (loosely coupled) یا جدا از هم باشند (decoupled).

اجازه دهید تا ببینیم که چه اتفاقی می افتد اگر کلاسهای ما به شدت به هم وابسته باشند:

XmlFileWriter یک کلاسی است که هدفش نوشتن درون یک فایل xml است. حالا ما میتوانیم کلاس XmlWriter  را نمونه سازی کنیم و آبجکت را از طریق سازنده XmlFileWriter ارسال کنیم و متد Write را فراخوانی کنیم:

اوکی تا اینجا همه چیزی عالی کار میکند.

اما ما اینجا چند مشکل داریم. کلاس XmlFileWriter ما به شدت به کلاس XmlWriter وابستگی دارد. اگر ما متد WriteFile را داخل کلاس XmlWriter تغییر دهیم سپس آن را باید در کلاس XmlFileWriter نیز تغییر دهیم. بنابراین تغییر در یک کلاس، منجربه تغییر در دیگری نیز میشود. کاری به این نداریم که میخواهیم کد ما چطور کار کند.

مسئله چیز دیگری است. ما قطعا میخواهیم همچین رفتاری را برای کلاس JsonWriter نیز داشته باشیم. ما نمیتوانیم از کلاس XmlFileWriter استفاده کنیم (زیرا آن فقط آبجکت XmlWriter را میپذیرد)، ما باید یک کلاس دیگر ایجاد کنیم و تمام اقدامات را برای این کلاس جهت استفاده از JsonWriter نیز تکرار کنیم که این خیلی میتواند بد باشد.

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

حال اجازه دهید کلاس XmlFileWriter را تغییر دهیم:

عالی. این یکی خیلی بهتر است.

حالا اینجا نام کلاس گویای این است که این کلاس فقط فایلهای xml نمینویسد. علاوه بر این، ما سازنده را فقط به پذیرش کلاس XmlWiter محدود نکرده ایم، بلکه به همه کلاسهایی که از اینترفیس IWriter ارث بری میکنند محدود کرده ایم. نام متد WriteFile نمیتواند تغییر کند چرا که اینترفیس IWritter بیان میکند که تمام کلاسها باید یک متد با یک نام یکسان را پیاده سازی کنند. حالا ما میتوانیم ببینیم که کلاس FileWriter مستقل از کلاس XmlWriter  یا JsonWriter است و اینکه ما میتوانیم آبجکتهای هر دو کلاس را به کلاس FileWriter بفرستیم:

آبجکتهای غیر وابسته #C

آیا این خیلی بهتر نیست؟

حالا ما یک کلاس داریم که کارش را برای هر کلاسی که از اینترفیس IWriter ارث بری میکند انجام میدهد.

این ویژگی به عنوان تزریق وابستگی (Dependency Injection) شناخته میشود.

کار کردن با چند اینترفیس

یک کلاس فقط میتواند از یک کلاس ارث بری کند، اما میتواند چند اینترفیس را پیاده سازی کند. آن کلاس باید تمام متدهای تعریف شده در آن اینترفیسها را پیاده سازی کند:

پیاده سازی صریح اینترفیس

همانطور که گفتیم، یک کلاس میتواند بیشتر از یک اینترفیس را پیاده سازی کند. غیرمعمول نیست که دو اینترفیس، یک متد هم نام داشته باشند، اما ما باید آنها را در کلاسمان پیاده سازی کنیم. از این جهت، ما نباید آن متدها را به شیوه قبل پیاده سازی کنیم، بلکه باید نام اینترفیس و سپس نام متد مورد نظر را به همراه پارامترهای آن بیان کنیم:

همانطور که میبینیم، ما در پیاده سازی متد، از access modifier استفاده نمیکنیم.

نتیجه گیری

در مقاله بعدی، در مورد کلاسهای Abstract در #C صحبت میکنیم.

نویسنده

امید عباسی
من امید عباسی هستم. سالهاست که در زمینه برنامه نویسی با تکنولوژی دات نت فعالیت میکنم و عاشق این هستم که تجربیات و دانش خودم را در این زمینه با دیگران به اشتراک بزارم. خیلی دوست دارم که نظر و انتقاد خودتون رو در مورد این نوشته برای من بنویسید تا بتونم در آینده، مطالب بهتر و ارزشمندتری را برای شما فراهم کنم. در صورت داشتن هرگونه سوال هم در قسمت دیدگاه ها میتونید با بنده در ارتباط باشید