PDA

توجه ! این یک نسخه آرشیو شده می باشد و در این حالت شما عکسی را مشاهده نمی کنید برای مشاهده کامل متن و عکسها بر روی لینک مقابل کلیک کنید : Lazy در دات نت ۴



Borna66
06-21-2010, 03:35 PM
Lazy در دات نت

۴ http://pnu-club.com/imported/mising.jpg




یکی از الگوهای برنامه نویسی شیء گرا، Lazy Initialization Pattern نام دارد که دات نت ۴

پیاده سازی آن‌ را سهولت بخشیده است.
در دات نت ۴ کلاس جدیدی به فضای نام System اضافه شده است به نام Lazy و هدف از آن lazy initialization است؛
من ترجمه‌ اش می‌کنم وهله سازی با تاخیر یا به آن on demand construction هم گفته‌اند و در واقع زمانی که به آن نیاز هست ساخته خواهد شد.
فرض کنید در برنامه‌ی خود نیاز به شی ای دارید و ساخت این شی بسیار پرهزینه است.
نیازی نیست تا بلافاصله پس از تعریف، این شی ساخته شود و تنها زمانیکه به آن نیاز است باید در دسترس باشد.
کلاس Lazy جهت مدیریت اینگونه موارد ایجاد شده است.
تنها کاری که در اینجا باید صورت گیرد، محصور کردن آن شیء هزینه ‌بر توسط کلاس Lazy است:





Lazy<expensiveresource> ownedResource = new Lazy</expensiveresource><expensiveresource>();
</expensiveresource>

Lazy ownedResource = new Lazy(); در این حالت برای دسترسی به شیء ساخته شده از ExpensiveResource ، می‌توان از خاصیت Value استفاده نمود (ownedResource.Value).
تنها در حین اولین دسترسی به ownedResource.Value ، شیء ExpensiveResource ساخته خواهد شد و نه پیش از آن و نه در اولین جایی که تعریف شده است.
پس از آن این حاصل cache شده و دیگر وهله سازی نخواهد شد.
ownedResource دارای خاصیت IsValueCreated نیز می‌باشد و جهت بررسی ایجاد آن شیء می‌تواند مورد استفاده قرار گیرد.
برای مثال قصد داریم اطلاعات ExpensiveResource را ذخیره کنیم اما تنها در حالتیکه یکبار مورد استفاده قرار گرفته باشد.
کلاس Lazy دارای دو متد سازنده‌ی دیگر نیز می‌باشد:



public Lazy(bool isThreadSafe);
public Lazy(Func<t> valueFactory, bool isThreadSafe);
</t>

public Lazy(bool isThreadSafe); public Lazy(Func valueFactory, bool isThreadSafe); و هدف از آن استفاده‌ی صحیح از این متد در محیط‌های چند ریسمانی است.
بدیهی است در این نوع محیط‌ ها علاقه‌ای نداریم که در یک لحظه توسط چندین ترد مختلف، سبب ایجاد وهله‌های ناخواسته‌ا‌ی از ExpensiveResource شویم و تنها یک مورد از آن کافی است یا به قولی thread safe, lazy initialization of expensive objects
اگر برنامه‌ی شما چند ریسمانی نیست می‌توانید این مکانیزم را کنسل کرده و اندکی کارآیی برنامه را با حذف قفل‌های همزمانی این کلاس بالا ببرید.
مثال اول:




using System;
using System.Threading;

namespace LazyExample
{
class Program
{
static void Main()
{
Console.WriteLine("Before assignment");
var slow = new Lazy<slow>();
Console.WriteLine("After assignment");

Thread.Sleep(1000);

Console.WriteLine(slow);
Console.WriteLine(slow.Value);

Console.WriteLine("Press a key...");
Console.Read();
}
}

class Slow
{
public Slow()
{
Console.WriteLine("Start creation");
Thread.Sleep(2000);
Console.WriteLine("End creation");
}
}
}
</slow>




using System; using System.Threading; namespace LazyExample { class Program { static void Main() { Console.WriteLine("Before assignment"); var slow = new Lazy(); Console.WriteLine("After assignment"); Thread.Sleep(1000); Console.WriteLine(slow); Console.WriteLine(slow.Value); Console.WriteLine("Press a key..."); Console.Read(); } } class Slow { public Slow() { Console.WriteLine("Start creation"); Thread.Sleep(2000); Console.WriteLine("End creation"); } } }

خروجی این برنامه به شرح زیر است:





Before assignment
After assignment
Value is not created.
Start creation
End creation
LazyExample.Slow
Press a key...


Before assignment After assignment Value is not created. Start creation End creation LazyExample.Slow Press a key... مثال دوم:
شاید نیاز به مقدار دهی خواص کلاس پرهزینه‌ وجود داشته باشد.
برای مثال علاقمندیم خاصیت SomeProperty کلاس ExpensiveClass را مقدار دهی کنیم.
برای این منظور می‌توان به شکل ذیل عمل کرد (یک Func<t>را می‌توان به سازنده‌ی آن ارسال نمود):



using System;

namespace LazySample
{
class Program
{
static void Main()
{
var expensiveClass =
new Lazy<expensiveclass>
(
() =>
{
var fobj = new ExpensiveClass
{
SomeProperty = 100
};
return fobj;
}
);

Console.WriteLine("expensiveClass has value yet {0}",
expensiveClass.IsValueCreated);

Console.WriteLine("expensiveClass.SomeProperty value {0}",
(expensiveClass.Value).SomeProperty);

Console.WriteLine("expensiveClass has value yet {0}",
expensiveClass.IsValueCreated);

Console.WriteLine("Press a key...");
Console.Read();
}
}

class ExpensiveClass
{
public int SomeProperty { get; set; }

public ExpensiveClass()
{
Console.WriteLine("ExpensiveClass constructed");
}
}
}
</expensiveclass>



using System; namespace LazySample { class Program { static void Main() { var expensiveClass = new Lazy ( () => { var fobj = new ExpensiveClass { SomeProperty = 100 }; return fobj; } ); Console.WriteLine("expensiveClass has value yet {0}", expensiveClass.IsValueCreated); Console.WriteLine("expensiveClass.SomeProperty value {0}", (expensiveClass.Value).SomeProperty); Console.WriteLine("expensiveClass has value yet {0}", expensiveClass.IsValueCreated); Console.WriteLine("Press a key..."); Console.Read(); } } class ExpensiveClass { public int SomeProperty { get; set; } public ExpensiveClass() { Console.WriteLine("ExpensiveClass constructed"); } } }

کاربردها:
- علاقمندیم تا ایجاد یک شی هزینه ‌بر تنها پس از انجام یک سری امور هزینه ‌بر دیگر صورت گیرد.
برای مثال آیا تابحال شده است که با یک سیستم ماتریسی کار کنید و نیاز به چند گیگ حافظه برای پردازش آن داشته باشید؟!
زمانیکه از کلاس Lazy استفاده نمائید، تمام اشیاء مورد استفاده به یکباره تخصیص حافظه پیدا نکرده و تنها در زمان استفاده از آن‌ها کار تخصیص منابع صورت خواهد گرفت.
- ایجاد یک شی بسیار پر هزینه بوده و ممکن است در بسیاری از موارد اصلا نیازی به ایجاد و یا حتی استفاده از آن نباشد.
برای مثال یک شی کارمند را درنظر بگیرید که یکی از خواص این شی، لیستی از مکان‌هایی است که این شخص قبلا در آنجاها کار کرده است.
این اطلاعات نیز به طور کامل از بانک اطلاعاتی دریافت می‌شود.
اگر در متدی، استفاده کننده از شیء کارمند هیچگاه اطلاعات مکان‌های کاری قبلی او را مورد استفاده قرار ندهد، آیا واقعا نیاز است که این اطلاعات به ازای هر بار ساخت وهله‌ای از شیء کارمند از دیتابیس دریافت شده و همچنین در حافظه ذخیره شود؟