PDA

View Full Version : استفاده از مخرب و سازنده



marzban
چهارشنبه 10 مرداد 1386, 09:02 صبح
با سلام
من تقریبا کم و بیش با مفاهیم مخرب ها و سازنده ها آشنای اندکی در حد مفاهیم دارم
می خوام که به یه نحوی ازشون در نوشتن کلاسهای مربوط به بانکهای اطلاعاتی اسفاده کنم . ولی در این مورد جیز زیادی به ذهن خودم نمی رسه آیا استفاده از سازنده و مخرب می تونه تو نوشتن این سبک برنامه نویسی کمک کنه.
لطفا راهنمایی کنید
با تشکر مرزبان

ghafoori
چهارشنبه 10 مرداد 1386, 14:29 عصر
دوست عزیز منظور شما از

استفاده از مخرب و سازنده
چیست منظور از استفاده از دستورات new و dispose است و مدیریت حافظه یا چیز دیگر

omid_Ahmadi
چهارشنبه 10 مرداد 1386, 15:15 عصر
منظور Constructor و Destructor هست، حالا به هر اسمی که در هر زبان مطرح شده باشه.

alireza1384
چهارشنبه 10 مرداد 1386, 15:44 عصر
دوست عزیزهمانطورکه حتما میدانی وقتی یک شی ازکلاسی تعریف می کنی ، سازنده کلاس به طورخودکارفراخوانی می شود. اگربخواهی فیلدی ازاین شی درزمان ایجادش مقداری بگیرد ( مثلانام کاربررا) می توانی سازنده را override نموده و این کاررا انجام دهی.
مخرب نیز آخرین دستوری است که قبل از ازبین رفتن یک شی فراخوانی می شودکه می توانی درآن جهت آزادسازی منابعی که این شی ازآنها استفاده می کند استفاده کنی ؛ البته .net این کاررا انجام می دهد ولی جهت اطمینان می توانی خودت به طوردستی اینکاررا بکنی . به عنوان مثال اگردربرنامه ات فایلی را بازکرده ای ( مثلایک فایل text) و درحال استفاده ازآن هستی می توانی درقسمت مخرب نسبت به بستن آن فایل اقدام کنی .

marzban
چهارشنبه 10 مرداد 1386, 16:58 عصر
ممنون از راهنمایی همه دوستان
به نظر شما کار درستی می تونه باشه که ایجاد کانکشن هام رو تو سازنده انجام بدم و بستن اونها رو تو مخرب ها
این کار چقدر می تونه به قدرت نرم افزار کمک کنه
ممنون می شم اگه راهنمایی کنید
با تشکر مرزبان

omid_Ahmadi
چهارشنبه 10 مرداد 1386, 18:30 عصر
این مورد به منطق کاری کلاس مورد نظر شما بستگی داره. باز بودن هر کانکشن به بانک اطلاعاتی مقداری از منابع سیستم رو به خودش تخصیص می ده و اتصال اون هم همین طور. یعنی هر دو اورهدی رو به سیستم تحمیل می کنن. پس هم اگر زیاد در برنامه به باز و بسته کردن کانکشن بپردازید، پرفورمنس رو تحت تاثیر قرار می دید و هم اگر زیاد کانکشن رو باز نگه دارید. باید بتونید بین این موارد تعادل برقرار کنید.

marzban
چهارشنبه 10 مرداد 1386, 20:02 عصر
از راهنمایی تون ممنون
خوب و قتی از معماری 3 لایه بخواهیم استفاده کنیم مسلما دفعات استفاده از یک کلاس زیاد میشه
لطف کنید بفرمایید وقتی برنامه چند یوزر فعال داشته باشه (برای مثال 5 تا 10یوزر) آیا اورهد ممکنه زیاد باشه(با این فرض که کاربران فعال باشند)
راه حل پیشنهادی برای نوشتن برنامه ای بهتر چی هست؟

با تشکر مرزبان

Behrouz_Rad
چهارشنبه 10 مرداد 1386, 22:39 عصر
استفاده از سازنده و مخرب بستگی به مورد کاربرد داره.
از سازنده زمانی استفاده کن که یک کلاس برای عملیاتی که قرار هست انجام بده، نیاز داره (یا میتونه نیاز داشته باشه) که مقداری رو به عنوان مقدار اولیه بگیره.


پس هم اگر زیاد در برنامه به باز و بسته کردن کانکشن بپردازید، پرفورمنس رو تحت تاثیر قرار می دی

این درسته اما در این مورد نمیشه کاری انجام داد.
به هر حال عملیات باید انجام بشه و نمیشه جلوی اون رو گرفت.
به لطف Connection Pooling و با مدیریت صحیح بستن کانکشن( using یا Finally)، پرفورمنس رو میشه به حداکثر میزان خودش رسوند.
مخرب ها زمانی فراخوانی میشن که مثلا متد Dispose ای از یک کلاس فراخوانی بشه و یا کلاس null بشه.
هر کلاسی معمولا به شکلی روال Disposing رو انجام میده.
مثلا شی SqlConnection با فراخوانی متد Close، به طور صریح متد Dispose خودش رو نیز فراخوانی میکنه.
در نهایت برای کاری که میخوای انجام بدی نیازی به استفاده از مخرب ها نداری.

موفق باشید.

omid_Ahmadi
چهارشنبه 10 مرداد 1386, 23:03 عصر
این درسته اما در این مورد نمیشه کاری انجام داد.
به هر حال عملیات باید انجام بشه و نمیشه جلوی اون رو گرفت.
فکر کنم درست متوجه منظور من نشدید، یه بار دیگه اگر پست منو با دقت بخونید میبینید که تناقضی با این گفته نداره، منظور من جلوگیری از افراط در باز و بسته کردن کانکشن هست که معمولاً در برنامه هایی که به صورت مبتدی نوشته میشه و یا در نوشتن اون از ویزاردها استفاده میشه زیاد به چشم می خوره.



خوب و قتی از معماری 3 لایه بخواهیم استفاده کنیم مسلما دفعات استفاده از یک کلاس زیاد میشه
لطف کنید بفرمایید وقتی برنامه چند یوزر فعال داشته باشه (برای مثال 5 تا 10یوزر) آیا اورهد ممکنه زیاد باشه(با این فرض که کاربران فعال باشند)
راه حل پیشنهادی برای نوشتن برنامه ای بهتر چی هست؟
این مورد که اورهد زیاد میشه و یا نه فقط به تعداد یوزرها بستگی نداره، به خیلی از فاکتورهای دیگه هم وابسته است. در کل روشهایی هم برای بهبود کارایی وجود دارن، مثل Connection Pooling که جناب راد بهشون اشاره کردن و یا موارد دیگه. اما اگر طراحی و پیاده سازی برنامه ضعیف باشه هیچ کدوم نمی تونن موثر واقع بشن.

موفق باشید.

Sajjad1364
پنج شنبه 11 مرداد 1386, 14:26 عصر
با سلام
تمام اشیایی که دارای مخرب هستند جداگانه توسطGarbage Collectorدر یک صف قرار میگیرند.چون معلوم نیست چه وقت شئ شما نابود میشود ,پس معلوم هم نیست کی کانکشن صریحا طبق خواسته شما بسته شود.وقتی که رفرنسی به یک شئ موجود نباشد,آن شئ در یک گراف (که از سوی Garbage Collector ساخته میشود,)قرار میگیرد.این گراف حاوی تمام اشیایی است که رفرنسی به آنها موجود نباشد.بنابر نیاز Garbage Collectorاین اشیاء را نابود میکند و حافظه را آزاد میکند.اما اشیایی که دارای مخرب اند از این گراف جدا میشوند و همانطور که گفتم جداگانه توسط Garbage Collector در صفی قرار داده میشوند.
Garbage Collector در این مرحله مخرب نوشته شده توسط برنامه نویس را به یک نسخه تحریف شده از متد مجازی Finalize در سطح شئ Object تبدیل میکند و آن را در یک بلاک try/catch/finally (برای کنترل خطاهای احتمالی) به مرحله اجرادر می آورد.
تمامی این مراحل مستلزم زمان میباشد(اگر فرض کنیم همه چیز بدون خطا اجرا میشود ) و صرف زمان یعنی از دست دادن کارایی.Garbage Collector در Thread خود اجرا میشود و زمان انجام هرگونه فعالیت بر تمامی Thread ها ارجحیت دارد و میتواند باعث تاخیر در کار برنامه شود.

mehdi.mousavi
پنج شنبه 11 مرداد 1386, 18:33 عصر
با سلام
من تقریبا کم و بیش با مفاهیم مخرب ها و سازنده ها آشنای اندکی در حد مفاهیم دارم
می خوام که به یه نحوی ازشون در نوشتن کلاسهای مربوط به بانکهای اطلاعاتی اسفاده کنم . ولی در این مورد جیز زیادی به ذهن خودم نمی رسه آیا استفاده از سازنده و مخرب می تونه تو نوشتن این سبک برنامه نویسی کمک کنه.
لطفا راهنمایی کنید
با تشکر مرزبان



سلام.
وقتی شما Object ای رو new می کنید، باعث میشید تا ctor اون Object فراخوانی بشه. اما در مورد destructor ها وقتی اون object رو null میذارید، destructor فراخوانی نمیشه. در واقع شما کنترلی روی زمان فراخوانی اون ندارید. destructor وقتی فراخوانی میشه که GC صلاح بدونه. اما GC چی هستش؟ Garbage Collector یا همون GC، مدیریت تخصیص و آزادسازی حافظه یه برنامه رو در .NET به عهده داره. همه چیز در heap مدیریت شده رخ میده، heap ای که بسیار شبیه Heap کدهای native هستش با این تفاوت که Object ها توسط برنامه نویس آزاد نمیشن، بلکه هنگامی آزاد میشن که دیگه نیازی بهشون نیست. (بد نیست بدونید که GC در درون خودش حاوی pointer به object هایی هستش که تو heap مدیریت شده نگه داشته میشه. به این pointer ها root میگن. وقتی برنامه شروع به کار میکنه یا هر وقت شما Object ای رو new می کنید، CLR یه graph از root ها رو میگیره و تو یه زمان از پیش تعیین شده شروع به آزاد سازی همه اون object هایی میکنه که root اونها null شده. هر وقت شما یه object ای رو که new کردین، مساوی null بذارین، سیستم تشخصی میده و root مربوط به اون object رو هم null میکنه تا بعدا بتونه سر فرصت اونهایی که null هستن رو، release کنه).

اما سیستم از کجا می خواد بفهمه که دیگه نیازی به یه Object نیست؟ برای فهمیدن جواب این سوال ایتدا باید بدونیم که C# دو نوع عمومی از type ها رو پشتیبانی میکنه: value type ها و Reference Type ها.

value-type ها تایپهای enum، built-in ها و struct ها هستن. اونها میتونند مستقیم مقادیر رو در خودشون حفظ کنن. Stack، حافظه ای هستش که این نوع تایپها توسط سیستم در اون نگهداری میشن. در مقابل reference-type ها رو داریم، که در واقع reference یا pointer به یک instance رو در stack نگه میدارن و خود instance رو در heap مدیریت شده. البته من قبلا در مورد value-type ها و reference ها در این پست (http://barnamenevis.org/forum/showpost.php?p=370112&postcount=3) توضیحاتی داده بودم که خوندنش خالی از لطف نیست.

اما چه اتفاقی می افته وقتی شما یه Object ای رو new می کنید؟ CLR فرض میکنه که حافظه سیستم نامحدوده و شروع به تخصیص حافظه بصورت ترتیبی می کنه. یعنی خونه به خونه حافظه رو میره جلو و اختصاص میده به Object هایی که شما new می کنید. اما واقعیت اینه که سیستم، حافظه محدودی داره و تا ابد نمیتونه این مساله ادامه پیدا کنه، پس یه نفر باید فضاهای بلا استفاده تو heap رو آزاد کنه و اینجاست که GC توسط root هایی که بالا توضیح دادم، اقدام به آزادسازی حافظه می کنه. اما هنوز یه کار دیگه هم باید انجام بشه، و اون Compact کردن حافظه هستش. اما همه این مراحل به نظرتون باندازه کافی سریع هستش؟ فکرش رو کنید، وقتی GC شروع به آزاد سازی حافظه کنه، باید بره لیست همه root هایی که مساوی null هستن رو بیاره و دونه به دونه اقدام به آزادسازی اونا کنه که کاملا مشخصه که بسیار روند کندی هستش.

پس اومدن گفتن جای اینکه تو یه فاز بریم و object هایی که root اونها الان null هست رو آزاد کنیم، بیاییم این کار رو تو چند مرحله انجام بدیم. اما با توجه به این مفروضات که اولا Compact کردن بخشی از heap سریعتر از compact کردن کل heap هستش و ثانیا Object های قدیمیتر احتمالا بیشتر باقی می مونن تا object های جدیدتر.

اما فازها: گفتن ما 3 تا فاز تعریف میکنیم. فاز اول وقتی هستش که یه object ای new میشه. همه object هایی که new میشن تو فاز 1 ذخیره میشن تا وقتی که فاز یک پر بشه. هر وقت این اتفاق افتادش، GC شروع به آزادسازی تمام Object هایی میکنه که دیگه جایی reference نشدن و مابقی که هنوز در حال استفاده هستن compact میشن و به سمت چپ میان. (حافظه رو خونه های چپ به راست افقی در نظر بگیرید). تمام Object هایی که باقی می مونن (یعنی هنوز در حال استفاده هستن)، میرن تو فاز 2. وقتیکه دوباره فاز 1 پر شدش، همه Object هایی که تو فاز 2 بودن میرن تو فاز 3. هر وقت هر 3 فاز پر بشن، OutOfMemoryException، داده میشه.

برای اینکه کاملا متوجه نحوه عملکرد .NET Framework ها بشید، مثال زیر رو در نظر بگیرید:


public class MyClass
{
public MyClass()
{
}

~MyClass()
{
}
}

MyClass myClass = new MyClass();
myClass = null;
GC.Collect();
GC.WaitForPendingFinalizers();

به این ترتیب وقتی کلاس myClass رو new میکنیم، باعث میشیم تا ctor فراخوانی بشه. بعد تو خط دوم myClass رو null میکنم، تا root معادل اون در managed-heap هم null بشه. بعد به GC میگم شروع به کار کنه و object های reference نشده رو آزاد کنه. (از جمله myClass رو). بعد به GC میگم که صبر کنه تا عملیات Collection تموم بشه. تازه تو این نقطه هستش که destructor کلاس فوق صدا زده میشه. تو حالت عادی، وقتی شما reference ای رو null میکنید، معلوم نیستش که کی destructor اش فراخوان میشه، چون هیچ اطلاعی از وضعیت فعلی حافظه مدیریت شده نداریم و تمام تصمیم گیری ها توسط GC انجام میشه.

پس این صحیح نیستش که بخواهیم رو destructor ها تو C# برنامه ریزی کنیم. اما بعضی اوقات هستش که شما تمایل دارید تا Object ای که دارید، عملیات مشخصی رو هنگام تخریب انجام بده. به این منظور IDisposable در .NET تعریف شد. هر وقت شما نیاز داشته باشید تا عملیات خاصی رو هنگام تخریب کلاس انجام بدین، باید کلاستون رو از IDisposable درایو کنید. به این ترتیب:


public class MyClass2 : IDisposable
{
public MyClass2()
{
}

public void Dispose()
{
}
}

و هنگام استفاده



MyClass2 myClass2 = new MyClass2();
myClass2.Dispose();
یا notation بهتر اون:


using (MyClass2 myClass2 = new MyClass2())
{
}
رو میتونید استفاده کنید. حالا با در دست داشتن این اطلاعات، دوباره برمیگردیم به سوال شما... کار کردن با بانکهای اطلاعاتی از طریق ADO.NET. چون در این تکنولوژی روندی به اسم Connection Pooling پشتیبانی میشه، توصیه همگان این هستش که بعد از اتمام کار با یه Connection، اونو از بین میبرین تا resource ها به سیستم بر گردن. در واقع ADO، منابع رو برای مدت محدودی نگه میداره، چون ممکنه شما مجددا تقاضای دسترسی به یه Connection رو داشته باشین... این بهترین روش در استفاده از ADO هستش... (راستش خسته شدم از بس نوشتم، اگه خدا بخواد بقیشو بعدا می نویسم).