در قسمت هشتم و پایانی آموزش شی گرایی مباحثی چون Interface یا رابط ها و Nested Type یا روابط تودرتو و تفاوت های Structها و Classها را آموزش داده ایم.امیدواریم کارایی لازم را داشته باشد.
یکی از قابلیت های Interface ها این است که قابلیت وراثت چندگانه را به ما میدهند چون همانگونه که میدانید وراثت چندگانه در سی شارپ امکان پذیر نیست اما اظ طریق Interfaceها یا رابط ها میتوان این امکان را بوجود آورد.
به مثال زیر دقت کنید
ابتدا کلاسی با نام Alives که به تمام جانداران اشاره دارد ایجاد کرده و درون پنجره کدنویسی آن ابتدا کلاسی که در واقع نقش کلاس پدر را ایفا میکند به شکل زیر ایجاد میکنیم
abstract class Alives { public abstract void Breath(); }
همانگونه که مشاهده میکنید کلاسی از نوع abstract ایجاد میکنیم(به این دلیل که نتوان از کلاس پدر شیی ایجاد کرد چئن از لحاظ منطقی نیز غیر معقول میبباشد) و متد یا هرعنصر دیگر که برای همه فرزندان یا زیرکلاسها صدق میکند را درون این کلاس قرار میدهیم که در این مثال متدی با عنوان Breath یا نوف کشیدن میباشد.
حال در ادامه زیر کلاس های دیگر را که از کلاس اصلی مشتق میشوند قید میکنیم البته به صورت Interface نه Class چون اگر آنهارا به صورت کلاس تعیین کنیم در ادامه اگر بخواهیم مثلا کلاسی تعیین کنیم که از چند زیر کلاس ارث بری کند با مشکل مواجه خواهیم شد بلکه تنها اجازه ارث بری از یک کلاس را داریم بنابراین از interface استفاده خواهیم کرد به شکل زیر
interface ICanivor { void EatMeat(); } interface IHerbivor { void EatGrass(); } interface IReptile { void Crawl(); }
همانگونه که مشاهده میکنید سه رابط با عنوانهای ICanivor(گوشت خوار) و IHebivar(گیاه خوار)و IReptile(خزنده) ایجاد شده و متدهای درونشان هم تنها معرفی شده چون بدنه آنها در زمان ارث بری تعیین میشود.
توجه فرمایید که برای ایجاد interfaceها تنها کافیست کلمه کلیدی interface و سپس نام دلخواه را قرار داد و دیگر نیازی به نوع خروجی و سطح دسترسی نیز نمیباشد حتی برای متدهای درونشان هم نیازی به سطح دسترسی نمیباشد تنها نوع خروجی و نام متد.
در ادامه نیز دو کلاس برای ارث بری چندگانه ایجاد کرده ایم
class Lion : Alives, ICa nivor { public override void Breath() { Console.WriteLine("Lion can Breath"); } public void EatMeat() { Console.WriteLine("Lion can Eat Meat"); } } class Aligator : Alives, ICanivor,IReptile { public override void Breath() { Console.WriteLine("Aligator can Breath"); } public void Crawl() { Console.WriteLine("Aligator can Crawl"); } public void EatMeat() { Console.WriteLine("Aligator can Eat Meata"); } }
class Lion : Alives, ICanivor { public override void Breath() { Console.WriteLine("Lion can Breath"); } public void EatMeat() { Console.WriteLine("Lion can Eat Meat"); } } class Aligator : Alives, ICanivor,IReptile { public override void Breath() { Console.WriteLine("Aligator can Breath"); } public void Crawl() { Console.WriteLine("Aligator can Crawl"); } public void EatMeat() { Console.WriteLine("Aligator can Eat Meata"); } }
دو کلاس Lion و Aligator همراه با کلاس های وارثشان که با کاما از هم جدا شده اند ایجاد کرده ایم و برای ایجاد بدنه متد درون هرکدام از کلاس های وارث آنهارا override(در آموزش های قبل به طور مفصل توضیح داده شده) کرده ایم و بدنه دلخواهی ایجاد کرده ایم.
رابطه های تو درتو در واقع عنصری میباشد که درون عنصر دیگر قرار دارد به طور مثال قلب درون بدن انسان خود یک سیستم واحد است اما تنها در درون بدن انسان معنی دارد و میتواند فعالیت کند و خارج از بدن انسان مفهوم خاصی ندارد.
در مثال زیر نیز ابتدا یک کلاس اصلی با عنوان انسان و درون آن یک کلاس دیگر با نام قلب ایجادشده
class Human { public string Name; Heart HumanHeart = new Heart(); public Heart HHeart { get { return HumanHeart; } set { HumanHeart = value; } } public class Heart { public int HeartBeat; } }
همانگونه که مشاهده میکنید ابتدا یک کلاس Heart درون کلاس Human ایجاد شده سپس برای شناساندن کلاس باید یک شی از همان نوع درون کلاس اصلی ایجاد کنیم تا بتوانیم در برنامه اصلی از طریق کلاس اصلی به کلاس درونش دسترسی پیدا کنیم بنابراین یک شی و پروپرتی از نوع کلاس Heart ایجاد میکینم.
حال درون main برنامه نیز میتوان چنین نوشت
static void Main(string[] args) { Human h = new Human(); h.HHeart.HeartBeat = 20; Console.WriteLine(h.HHeart.HeartBeat); Console.ReadKey(); }
همانگونه که مشاهده میکنید درون برنامه اصلی ابتدا یک شی از نوع کلاس اصلی که Human میباشد ایجاد میکنیم چون برنامه کلاس Heart که درون کلاس Human میباشد را نمیشناسد و ما باید از طریق کلاس اصلی به کلاس درون دسترسی پیدا کنیم بنابراین پس از ایجاد شی از کلاس اصلی به پروپرتی که از نوع کلاس Heart ایجاد کرده ایم دسترسی پیدا میکنیم سپس به عناصر درون کلاس Heart که در این مثال فیلدHeartBeat میباشد.
یک از تفاوت های structure ها با کلاسها این است که Struct ها نمیتوان در یک رابطه وراثت باشند بدین معنی که نمیتوان از یک struct ارث بری کنیم و یا به عنوان پدر قرار بگیرند.
تفاوت دیگر این است که structها value type هستند بدین معنی که اگر دو شی از نوع struct را به هم انتساب دهیم مقدار طرف راست درون طرف چپ کپی میشود برخلاف کلاس ها که امکان اینکار نیست.
مثال زیر نیز همین عمل را مشخص میکند
struct SampleStruct { public int number; public SampleStruct(int number) { this.number = number; } }
ما یک کلاس جدید ایجاد کرده ایم و بجای عبارت Class عبارت Struct را جایگزین کرده ایم تا به یک Structure تبدیل میشود و درو بدنه آن نیز یک فیلد و یک سازنده که توسط پارامتر مقدار را به فیلد میدهد.
*دو نکته که در رابطه با struct ها باید در نظر داشته باشید یکی این است که نمیتوان فیلدهارا به طور صریح مقدار دهی کرد بلکه حتما باید از طریق سازنده اینکار را انجام داد.
*نکته دیگر این است که سازنده درون struct حتما باید دارای پارامتر باشد و سازنده بدون پارامتر مجار نمیباشد.
در ادامه مثال درون برنامه اصلی چنین کدنویسی میکنیم
static void Main(string[] args) { SampleStruct s1 = new SampleStruct(12); SampleStruct s2=s1; s1.number = 10; Console.WriteLine(s1.number); Console.WriteLine(s2.number); Console.ReadKey(); }
همانگونه که مشاهده میکنید به دوصورت میتوان از یک struct شی ایجاد کرد که هر دو نوع مشخص شده البته باید توجه داشت که نوع دوم ا حتما باید مقداردهی کرد که در مثال فوق نیز شی اول را درون شی دوم قرار داده ایم و مقدار ۱۲ که در سازنده تعیین شده را درون s2 کپی میکند و درون s1 را نیز مقدار جدید ۱۰ قرار میدهد و نتیجه هارا چاپ میکنیم که نتیجه نیز به همین صورت خواهد بود
//OutPut
۱۰
۱۲
حال اگر همین دستورات را برای Class به شکل زیر قرار دهیم نتیجه متفاوت خواهد بود چون کلاس ها بر خلاف struct ها از نوع Reference Type هستند و در واقع هر دو اشاره گر هایی هستند که به یک کلاس اشاره دارند.
class RefClass { public int num = 10; } ////////////////////////////////////// static void Main(string[] args) { RefClass r1 = new RefClass(); r1.num = 10; RefClass r2 = r1; r2.num = 12; Console.WriteLine(r1.num); Console.WriteLine(r2.num); Console.ReadKey(); }
حال در این مثال چئن r1 , r2 هر دو از نوع کلاس هستند پس هردو به یک شی یکسان اشاره دارند که تغییر مقدار num درهرکدام از این اشیا مقدار هردو شی تغییر میکند
//OutPut
۱۲
۱۲
در کل میتوان گفت structها بیشتر در جاهایی استفاده میشود که بخواهیم از مباحث و اطلاعات سبک تر استفاده کنیم بر خلاف کلاسها که میتوان اطلاعت حجیمی را درونشان قرار داد.