PDA

View Full Version : نکات فنی در شی گرایی



fazel-d
سه شنبه 20 مرداد 1388, 12:03 عصر
این تا تایپیک رو ایجاد کردم تا هم خودم و دیگر دوستان ، بیشتر با این نکات آشنا بشن

سوال اولم اینه که Interface ها چی هستند و کاربرد آنها در کجاست؟
2- چه زمانی از کلمه کلیدی Virtual ، Static ، Sealed استفاده می شه؟
از دوستانی که خارج از سوالات پرسیده شده ، نکاتی را هم از شی گرایی ارسال می کنند ، کمال تشکر را دارم. چرا که تقاضا دارم این تایپیک صرفا جهت پاسخ به سوالات نباشد.

Sociant
سه شنبه 20 مرداد 1388, 16:10 عصر
تو اینترنت و تو همین سایت مقاله های خوبی راجع به شی گرایی موجوده ، خصوصا از آقای کیانی
ولی به شخصه معتقدم هرچه راجع به شی گرایی مطلب بخونیم و بنویسیم بازم کمه!

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

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

...

fazel-d
پنج شنبه 22 مرداد 1388, 12:39 عصر
interface ها ساختارهایی شبيه كلاسها هستند و مانند کلاسها شامل property, method, indexer, event میباشند. ولي با اين تفاوت كه اين اجزا بصورت abstract در اينترفيس قرار ميگيرند نه بصورت concrete. يعني اين اجزا بدون بدنه در اينترفيس تعريف ميشوند.

از طريق اينترفيس شما ميتوانيد يك كلاس را مجبور كنيد كه از قانوني خاص تبعيت كند. چگونه؟؟ از طريق اجزا (member) هايي كه در اينترفيس تعريف ميكنيد؛ و آن كلاس را مجبور ميكنيد كه اين اجزا را حتماً پياده سازي كند.

interface IShape
{
string Name { get; }
double GetArea();
double GetPerimeter();
}

class Circle : IShape
{
private double _radius;
public double Radius
{
get { return _radius; }
set { _radius = value; }
}

public string Name
{
get { return "Circle"; }
}

public double GetArea()
{
return this._radius * this._radius * Math.PI;
}

public double GetPerimeter()
{
return this._radius * 2 * Math.PI;
}
}در اينجا از طريق اينترفيس IShape، كلاس Circle رو مجبور كرديم كه اجزاي اين اينترفيس را پياده سازي كند. اگر در اين كلاس اين دو متد و پروپرتي Name وجود نداشته باشد كامپايلر به شما خطا ميدهد.

حالا اين اجبار به چه درد ميخورد؟ چه استفاده اي از آن ميشود؟ استفاده از اينترفيسها را interface polymorphism ميگويند. يعني پلي مرفيسم ار طريق اينترفيس. نوع ديگري پلي مرفيسم داريم كه به آن inheritance polymorphism ميگويند كه با آن كاري نداريم.

پلي مرفيسم به چه دردي ميخورد؟ از طريق پلي مرفيسم شما ميتونيد يك عمل را براي طيف خاصي از كلاسها، عمومي (General) كنيد. يعني چه؟ يعني فقط يكبار يك عمل خاص بنويسيد و براي "چند كلاس هم خانواده" از آن استفاده كنيد و به اصطلاح از كد خود "فاكتور گيري" كنيد. پلي مرفيسم يعني اينكه يك شيء‌ رفتار متفاوت از خود نشان دهد. چطوري؟ در پست بعدي به آن خواهيم پرداخت.
منبع: DotNetSource.Com
(http://www.dotnetsource.com) با تشکر از حمید قادری

fazel-d
پنج شنبه 22 مرداد 1388, 13:00 عصر
خب گفتیم که به لطف پلی مرفیسم میشود یک عمل خاص را برای چند کلاس هم خانواده بصورت عمومی نوشت، به جای اینکه این عمل را برای تک تک این کلاسها جداگانه بنویسیم.

حالا مثال رو کامل میکنیم و کلاس مستطیل (Rectangle) رو اضافه میکنیم

class Rectangle : IShape
{
private double _width;
public double Width
{
get { return _width;}
set { _width = value;}
}

private double _height;
public double Height
{
get { return _height;}
set { _height = value;}
}

public string Name
{
get { return "Rectangle"; }
}

public double GetArea()
{
return this._width * this._height;
}

public double GetPerimeter()
{
return (this._width + this._height) * 2;
}
}
خب پس دو کلاس Circle و Rectangle رو نوشتیم و اینترفیس IShape رو اصطلاحاً در آنها implement کردیم. حالا این دو کلاس 2 متد و یک پروپرتی یکسان دارند ولی با بدنه متفاوت و پیاده سازیهای مختلف.

interface polymorphism چه شد؟
خب حالا یک مساله: میخواهیم متدی بنویسیم که در ورودی یک شکل هندسی بگیرد و مشخصات آن را چاپ کند. بدون استفاده از اینترفیس مجبوریم برای هر شکل یک متد مجزا بنویسیم.

private void DisplayCircleInfo(Circle c)
{
Console.WriteLine("Shape Name: " + c.Name);
Console.WriteLine("Shape Area: " + c.GetArea());
Console.WriteLine("Shape Perimeter: " + c.GetPerimeter());
}

private void DisplayRectangleInfo(Rectangle r)
{
Console.WriteLine("Shape Name: " + r.Name);
Console.WriteLine("Shape Area: " + r.GetArea());
Console.WriteLine("Shape Perimeter: " + r.GetPerimeter());
}
وقتی اینترفیس نداریم از روش بالا استفاده میکنیم. اما از طریق اینترفیس میتوان کد بالا را یکی کرد!

private void DisplayInfo(IShape shape)
{
Console.WriteLine("Shape Name: " + shape.Name);
Console.WriteLine("Shape Area: " + shape.GetArea());
Console.WriteLine("Shape Perimeter: " + shape.GetPerimeter());
}
مگر میشود هم شیء Circle و هم شیء Rectangle به این متد پاس کرد؟ بله! چون هم Circle و هم Rectangle خود نوعی IShape هستند و در تعریف کلاسها با عملگر : این اینترفیس را پیاده سازی کردیم. بنابراین با این متد میتوان اطلاعات هر شیئی را که از اینترفیس IShape پشتیبانی میکند چاپ کرد.

Circle c = new Circle();
c.Radius = 3;
DisplayInfo(c);

Rectangle r = new Rectangle();
r.Width = 5;
r.Height = 4;
DisplayInfo(r);
بنابراین تا اینجا ما از کد خود فاکتور گیری کردیم و برای چاپ از یک متد استفاده کردیم. اما کجای کد ما پلی مرفیک است؟ کدام شیء رفتار متفاوت دارد؟ در متد آخر (DisplayInfo) شیء shape دارای رفتارهای متفاوت است! چون اگر Circle باشد یک تکه کد از کلاس Circle اجرا میشود و اگر Rectangle باشد یک تکه کد دیگر از کلاس Rectangle!!! (میتوان با گذاشتن break point و trace برنامه به این موضوع پی برد)


منبع: DotNetSource.Com
(http://www.dotnetsource.com/) با تشکر از حمید قادری

fazel-d
پنج شنبه 22 مرداد 1388, 13:07 عصر
چه زمانی از کلمه کلیدی Virtual ، Static ، Sealed استفاده می شه؟
یه سوال دیگه: [یه مقداری مثالا SATAthread] چیه که بالای یه کلاس یا متد ، اگه اشتباه نکنم میارن . امیدوارم منظورم را رسانده باشم.

fazel-d
شنبه 24 مرداد 1388, 13:38 عصر
همان طور که از اسمش پیداست به معنی تغییر دهنده مهرو موم شده است.
خوب این خاصیت به ما این امکان رو میده که از ارث بری ازکلاس ما یا از Override کردن متدهای ما جلوگیری کند.
به عنوان مثال: کلاس B از کلاس A ارث برده است. ولی هیچ کلاسی نمی تواند از کلاس B ارث برد.

class A {}
sealed class B : A {}


مثال 2 در مورد توابع:

class A
{
protected virtual void F() { Console.WriteLine("A.F");}
protected virtual void F2() { Console.WriteLine("A.F2");}
}
class B : A
{
sealed protected override void F() { Console.WriteLine("B.F");}
protected override void F2() {Console.WriteLine("A.F3");}
}
class C : B
{
// Attempting to override F causes compiler error CS0239.
// protected override void F() { Console.WriteLine("C.F"); }

// Overriding F2 is allowed.
protected override void F2() { Console.WriteLine("C.F2"); }
}

Cاز B ارث می برد.اما C نمی تواند از تابع مجازی F که در A تعریف شده و در B ، مهرو موم شده استفاده کند.

منبع MSDN
خوب چه زمانی خوبه که از Sealed Modifier استفاده بشه؟

fazel-d
پنج شنبه 09 مهر 1388, 11:14 صبح
اما موضوعی که بسیار در کلاسهای پایه ای خوده DotNet دیده می شه اینه که می شه برخی از توابع موجود رو سربارگذاری کرد و اجرای اون تابع را به دلخواه خود در آورد. مانند تابع OnPaint
خوب برای override کردن هم باید تابع در کلاس پایه به صورت Modifier ای از virtual نوشته بشه

reza_arab
یک شنبه 20 دی 1388, 00:15 صبح
خب گفتیم که به لطف پلی مرفیسم میشود یک عمل خاص را برای چند کلاس هم خانواده بصورت عمومی نوشت، به جای اینکه این عمل را برای تک تک این کلاسها جداگانه بنویسیم.

حالا مثال رو کامل میکنیم و کلاس مستطیل (Rectangle) رو اضافه میکنیم

class Rectangle : IShape
{
private double _width;
public double Width
{
get { return _width;}
set { _width = value;}
}

private double _height;
public double Height
{
get { return _height;}
set { _height = value;}
}

public string Name
{
get { return "Rectangle"; }
}

public double GetArea()
{
return this._width * this._height;
}

public double GetPerimeter()
{
return (this._width + this._height) * 2;
}
}
خب پس دو کلاس Circle و Rectangle رو نوشتیم و اینترفیس IShape رو اصطلاحاً در آنها implement کردیم. حالا این دو کلاس 2 متد و یک پروپرتی یکسان دارند ولی با بدنه متفاوت و پیاده سازیهای مختلف.

interface polymorphism چه شد؟
خب حالا یک مساله: میخواهیم متدی بنویسیم که در ورودی یک شکل هندسی بگیرد و مشخصات آن را چاپ کند. بدون استفاده از اینترفیس مجبوریم برای هر شکل یک متد مجزا بنویسیم.

private void DisplayCircleInfo(Circle c)
{
Console.WriteLine("Shape Name: " + c.Name);
Console.WriteLine("Shape Area: " + c.GetArea());
Console.WriteLine("Shape Perimeter: " + c.GetPerimeter());
}

private void DisplayRectangleInfo(Rectangle r)
{
Console.WriteLine("Shape Name: " + r.Name);
Console.WriteLine("Shape Area: " + r.GetArea());
Console.WriteLine("Shape Perimeter: " + r.GetPerimeter());
}
وقتی اینترفیس نداریم از روش بالا استفاده میکنیم. اما از طریق اینترفیس میتوان کد بالا را یکی کرد!

private void DisplayInfo(IShape shape)
{
Console.WriteLine("Shape Name: " + shape.Name);
Console.WriteLine("Shape Area: " + shape.GetArea());
Console.WriteLine("Shape Perimeter: " + shape.GetPerimeter());
}
مگر میشود هم شیء Circle و هم شیء Rectangle به این متد پاس کرد؟ بله! چون هم Circle و هم Rectangle خود نوعی IShape هستند و در تعریف کلاسها با عملگر : این اینترفیس را پیاده سازی کردیم. بنابراین با این متد میتوان اطلاعات هر شیئی را که از اینترفیس IShape پشتیبانی میکند چاپ کرد.

Circle c = new Circle();
c.Radius = 3;
DisplayInfo(c);

Rectangle r = new Rectangle();
r.Width = 5;
r.Height = 4;
DisplayInfo(r);
بنابراین تا اینجا ما از کد خود فاکتور گیری کردیم و برای چاپ از یک متد استفاده کردیم. اما کجای کد ما پلی مرفیک است؟ کدام شیء رفتار متفاوت دارد؟ در متد آخر (DisplayInfo) شیء shape دارای رفتارهای متفاوت است! چون اگر Circle باشد یک تکه کد از کلاس Circle اجرا میشود و اگر Rectangle باشد یک تکه کد دیگر از کلاس Rectangle!!! (میتوان با گذاشتن break point و trace برنامه به این موضوع پی برد)


منبع: DotNetSource.Com
(http://www.dotnetsource.com/) با تشکر از حمید قادری
سلام آقا فاضل
متد private void DisplayInfo(IShape shape) کجا پیاده سازی می شود؟ مگه نفرمودید اینترفیس ها پیاده سازی ندارند؟ اگر هم خود کلاس دایره و مستطیل بایستی این متد را پیاده سازی کنند هر چند که بدنه دو متد یکسان است اما در هر دو کلاس باید این بدنه را نوشت؟ یا اینکه من تصور اشتباهی دارم
ممنون

gh-reza
یک شنبه 20 دی 1388, 13:46 عصر
اگه یه متغیر یا متد متعلق به کلاس static تعریف بشه یعنی به ازای کلاس یک نمونه از اون وجود خواهد داشت. دسترسی به اون متغیر یا متد هم از طریق نام کلاس خواهد بود نه اشیاء درست شده از اون کلاس. مثلا Math.Sin بدون تعریف شیءای از نوع کلاس Math و فقط با نام کلاس فراخوانی میشه. یکی از متدهای static متد Main هست که چون از بیرون از C# فراخوانی میشه (یعنی زمانی که هنوز هیچ شیءای بوجود نیومده) باید static باشه.

fazel-d
یک شنبه 20 دی 1388, 21:06 عصر
در پیرو سوال زیر

تد private void DisplayInfo(IShape shape) کجا پیاده سازی می شود؟ مگه نفرمودید اینترفیس ها پیاده سازی ندارند؟ اگر هم خود کلاس دایره و مستطیل بایستی این متد را پیاده سازی کنند هر چند که بدنه دو متد یکسان است اما در هر دو کلاس باید این بدنه را نوشت؟ یا اینکه من تصور اشتباهی دارمباید گفت که :
Interface ها همانند کلاس ها تعریف شده و در جلوی نام کلاس ها با علامت : به ارث برده می شوند.
نکته: هر کلاس تنها، از یک کلاس دیگر و از چندین Interface می تواند ارث ببرد. (محدودیت در ارث بری کلاسها)

اینکه کجا متد DisplayInfo(IShape shape نوشته می شه ؟ در کلاس والد. مثلا form1.cs. ونیازی به override کردن ایم متد در کلاس دایره و ... نیست.

mdssoft
شنبه 10 بهمن 1388, 15:25 عصر
ممنون از توضیحات خوبتون.


اینکه کجا متد DisplayInfo(IShape shape نوشته می شه ؟ در کلاس والد. مثلا form1.cs. ونیازی به override کردن ایم متد در کلاس دایره و ... نیست.

میشه یه نمونه کد بزارید ! من درست متوجه نشدم.