با توجه به اینکه الگوهای طراحی زیادی وجود دارند، چگونه میتوانید مناسبترین الگوی طراحی را برای حل مسئله خود انتخاب کنید و مهمتر اینکه چگونه آن را اعمال نمایید؟ برای پاسخ به این سوال، رهنمودهای زیر را همیشه در نظر داشته باشید:
- شما نمیتوانید یک الگو را به کار بگیرید مگر آنکه آن را به خوبی فهمیده باشید. بنابراین در اولین گام باید اصول و الگوهای طراحی را هم به شکل انتزاعی و هم به شکل واقعی خوانده و تمرین کنید. دقت کنید که یک الگو را به شکلهای مختلفی میتوان پیاده سازی کرد. هر چه پیاده سازیهای بیشتری ببینید، به هدف و چگونگی استفاده از آن بهتر مسلط میشوید.
- آیا میخواهید با استفاده از یک الگوی طراحی، برنامه خود را پیچیدهتر کنید؟ این معمول است که توسعه دهندگان برای حل هر مسئله از الگوهای طراحی استفاده میکنند. ابتدا هزینه و فایده پیاده سازی یک الگو را ارزیابی کرده، سپس اقدام به استفاده کنید. همیشه قاعده KISS را به خاطر داشته باشید.
- مسئله خود را تعمیم دهید. پیامدهای مسئله خود را با دید انتزاعی و سطح بالا بررسی کنید. به یاد داشته باشید که الگوهای طراحی، راه حلهای سطح بالا برای مسائل سطح بالا هستند. بنابراین روی پیامدهای جزئی یا وابسته به دامین مسئله خود تمرکز نکنید.
- به الگوهای مشابه و هم گروه نگاه کنید. اگر قبلا از یک الگو استفاده کردهاید بدین معنی نیست برای هر مسئلهای آن الگو درست است.
- هر چیزی که تغییر میکند را بسته بندی کنید. ببینید که چه چیزی در برنامه کاربردی شما ممکن است تغییر کند. اگر شما میدانید که یک الگوریتم اعمال تخفیف ممکن است به مرور زمان تغییر کند، به دنبال الگویی باشید که تغییرات در آن الگوریتم را بدون تاثیر بر سایر قسمتهای برنامه کاربردی انجام دهید.
- وقتی که یک الگو را انتخاب کردید، از زبان الگو در کنار زبان دامین برای نام گذاری کلاسها استفاده کنید. برای مثال اگر ازالگوی Strategy استفاده میکنید تا هزینه حمل و نقل کالا توسط شرکت FedEx را محاسبه کند، از نام FedExShippingCostStrategy استفاده کنید. با استفاده از زبان مشترک بین الگو طراحی و مدل دامین، کد برنامه برای شما و دیگران خواناتر و قابل فهمتر میگردد.
- همیشه منظور هر الگو را در ذهن خود مرور کنید و هنگام برخورد با یک مسئله به دنبال مناسبترین الگو بگردید. یک تمرین یادگیری عالی شناسایی الگوهای طراحی در فریم ورک .Net است. برای مثال، ASP.Net Cache از الگوی Singleton استفاده میکند و کلاس Guid از الگوی Factory بهره میبرد.
تا به حال شما باید هدف و الگوریتم استفاده از الگوهای طراحی را درک کرده باشید. در ادامه با لایه بندی برنامه کاربردی آشنا میشوید و سپس نحوه استفاده از این الگوها در لایههای مختلف را فرا خواهید گرفت.
در قسمت قبل با الگوریتم Association Rules که بیشتر برای تحلیل سبد خرید استفاده میشد، آشنا شدیم. در این قسمت که قسمت آخر از سری مقالات الگوریتمهای داده کاوی در SSDT میباشد، با الگوریتمهای Neural Network و Logistic Regression آشنا میشویم.
مقدمه
روشی کار مغز انسان برای حل مسالهای که با آن مواجه میشود را درنظر بگیرید. ابتدا حقایق مساله را در چند سطح تحلیل کرده و میسنجد. سپس این حقایق، وارد نرونهای عصبی میشوند. این نرونهای عصبی مانند فیلترهایی که براساس الگوهای معلوم قبلی عمل میکنند، شروع به فیلتر کردن حقایق مینمایند. درنهایت این موضوع سبب استنتاج میگردد که ممکن است منجر به پیدا کردن راه حلی برای مساله شود و یا به عنوان وقایع افزودهای برای از سرگیری مراحل بالا در نرونهای عصبی دیگر باشد.
توصیف الگوریتم
الگوریتم هوش مصنوعی مایکروسافت، نرونهای عصبی مصنوعی را بین ورودیها و خروجیها، برقرار میسازد و از آنها به عنوان الگو برای پیش بینیهای آینده استفاده مینماید. مزیت این الگوریتم نسبت به الگوریتمهای دیگر، کشف روابط خیلی پیچیده بین ورودیها و خروجیها است. البته نسبت به الگوریتمهای دیگر زمان بیشتری را جهت ساخت و آموزش مدل استفاده میکند.پیچیدگی تحلیل انجام شده توسط این الگوریتم به دو عامل بر میگردد:
- ممکن است یک یا تمام ورودیها به طریقی با یک یا همهی خروجیها مرتبط باشند و الگوریتم باید این موضوع را در آموزش مدل درنظر بگیرد.
- ممکن است ترکیبات مختلفی از ورودیها به طریقی با خروجیها در ارتباط باشند.
دسته بندی اسناد یکی از موضوعاتی است که شبکههای عصبی بهتر از الگوریتمهای دیگر آن را حل میکنند. البته اگر سرعت برای ما مهم باشد، میتوان از الگوریتم Naïve Bayes استفاده کرد. اما درصورتیکه دقت مهمتر باشد، آنگاه باید از الگوریتم شبکههای عصبی استفاده نمود.
تفسیر مدل
نتیجهی حاصله از این الگوریتم نسبت به الگوریتمهای قبلی کاملا متفاوت است. در اینجا دیگر خبری از طرح محتوای مدل و نمودار گرافیکی لایه آموزش نیست. هدف اصلی در اینجا نمایش تاثیر صفت-مقدار، بر ویژگی قابل پیش بینی است. برای مثال جدول زیر در رابطه با تمایل به خرید یا اجاره خانه در رابطه با صفات مختلف میباشد. همانطور که مشخص است، دو ستون اول نشان دهندهی جفت صفت-مقدار و دو ستون دوم، صفت مدنظر جهت پیش بینی را نشان میدهند. براساس این جدول میتوان نتیجه گرفت که مهمترین فاکتور در تمایل به خریداری خانه، سن افراد میباشد. افرادی که سنی بین 38 تا 54 سال را دارند، بیشترین تمایل را در خرید یک خانه دارند. فاکتورهایی مانند متاهل بودن، سطح تحصیلات فوق دکترا، بازه سنی 33 تا 38 و خانم بودن نیز دارای اهمیت میباشند که به ترتیب از درجه اهمیت آنها کم میشود. از طرفی بازه سنی 20 تا 28 سال بیشترین تمایل برای اجاره خانه را دارند. همچنین میتوان گفت که افرادی که مجرد هستند، طلاق گرفتهاند و یا سطح تحصیلاتشان دبیرستان است، بیشتر تمایل به اجاره خانه دارند تا به خرید آن.
Logistic Regression
همانند الگوریتم شبکههای عصبی است؛ با این تفاوت که لایه مخفیای برای تولید ترکیبی از ورودیها ندارد. یعنی سعی در برقراری ارتباط بین ترکیبی از ورودیها و خروجیها نمیکند (در واقع همان الگوریتم شبکههای عصبی است که پارامتر Hidden Node Ratio آن روی صفر تنظیم شده است). بنابراین سرعت پردازش و آموزش مدل در آن، بالاتر میباشد. البته صرف اینکه این الگوریتم دارای پیچیدگی کمتری است نمیتوان گفت که همیشه ضعیفتر از الگوریتم شبکههای عصبی است. بلکه حتی در بعضی از مدلها بهتر از الگوریتم شبکههای عصبی عمل میکند و مانع از باز آموزشی مدل میگردد.
به پایان آمد این دفتر، حکایت همچنان باقی است!
باسپاس فراوان از تمامی دوستانی که در این مدت سری مقالات الگوریتمهای داده کاوی را دنبال نمودند. از آنجاکه هر یک از الگوریتمها، دارای ریزه کاریهای به خصوصی است، بنابراین انتخاب الگوریتم مناسب در رابطه با داده کاوی بسیار حائز اهمیت میباشد و به دلیل فرّار بودن این ریزه کاریها، در گذشته بنده هر زمانیکه نیاز به داده کاوی داشتم مجبور بودم مطالب مربوط به الگوریتمها را مطالعه کنم تا بتوانم بهترین الگوریتم (ها) را در رابطه با داده کاوی مدنظر انتخاب نمایم. در نتیجه برآن شدم تا چکیدهای نسبتا کارا را از این الگوریتمها که در این شش قسمت آورده شد، تهیه و در اختیار عموم قرار دهم. به امید موفقیت و پیشرفت روز افزون تمامی برنامه نویسان و توسعه دهندگان ایرانی.
[Column(TypeName = "xml")] public string XmlValue { get; set; } [NotMapped] public XElement XmlValueWrapper { get { return XElement.Parse(XmlValue); } set { XmlValue = value.ToString(); } }
روش عمومی کار با نوعهای خاصی که در EF تعریف نشدن، استفاده از ویژگی Column و مشخص کردن Type آن است؛ مانند مثالی که در بالا ملاحظه میکنید. البته این نوع خاص، در سمت کدها باید به صورت رشته تعریف شود. مثلا از سال 2005 به این طرف فیلد XML به SQL Server اضافه شده. اما نمیشود ازش در EF به همون شکل XML استفاده کرد. باید تبدیلش کنی به String تا قابل استفاده بشه. یک نمونه دیگرش نوع خاص Spatial هست که در نگارشهای اخیر SQL Server اضافه شده (geography و geometry). این مورد فقط از EF 5.0 به بعد پشتیبانی توکاری ازش ارائه شده. یا برای hierarchyID در EF معادلی وجود نداره. برای تعریف این مورد نیز در یک مدل باید از string استفاده کرد.
بعد اگر این نوع خاص (که الان به صورت رشته دریافت شده) قابل نگاشت به نوعی مشخص در سمت کدهای برنامه بود (یعنی صرفا یک رشته ساده نبود) مثلا میشود از ویژگی NotMapped برای تبدیل آن و تعریف آن به شکل یک فیلد محاسباتی استفاده کرد.
ایجاد گزارش با داده های ثابت و متغیر
public class Rpt { public string Title {set;get;} public int Price {set;get;} }
var list = new List<Rpt>(); list.Add(new Rpt{ Title = "عنوان دلخواه", Price = 1});
پس از ساخت لیست، از منبع داده StronglyTypedList استفاده کنید. یک مثال از این منبع داده
حذف موجودیتهای منفصل
فرض کنید موجودیتی را از یک سرویس WCF دریافت کرده اید و میخواهید آن را برای حذف علامت گذاری کنید. مدل زیر را در نظر بگیرید.
همانطور که میبینید مدل ما صورت حسابها و پرداختهای متناظر را ارائه میکند. در اپلیکیشن جاری یک سرویس WCF پیاده سازی کرده ایم که عملیات دیتابیسی کلاینتها را مدیریت میکند. میخواهیم توسط این سرویس آبجکتی را (در اینجا یک موجودیت پرداخت) حذف کنیم. برای ساده نگاه داشتن مثال جاری، مدلها را در خود سرویس تعریف میکنیم. برای ایجاد سرویس مذکور مراحل زیر را دنبال کنید.
- در ویژوال استودیو پروژه جدیدی از نوع WCF Service Library بسازید و نام آن را به Recipe5 تغییر دهید.
- روی پروژه کلیک راست کنید و گزینه Add New Item را انتخاب کنید. سپس گزینههای Data -> ADO.NET Entity Data Model را برگزینید.
- از ویزارد ویژوال استودیو برای اضافه کردن یک مدل با جداول Invoice و Payment استفاده کنید. برای ساده نگه داشتن مثال جاری، فیلد پیمایشی Payments را از موجودیت Invoice حذف کرده ایم (برای این کار روی خاصیت پیمایشی Payments کلیک راست کنید و گزینه Delete From Model را انتخاب کنید.) روی خاصیت TimeStamp موجودیت Payment کلیک راست کنید و گزینه Properties را انتخاب کنید. سپس مقدار Concurrency Mode آن را به Fixed تغییر دهید. این کار باعث میشود که مقدار این فیلد برای کنترل همزمانی بررسی شود. بنابراین مقدار TimeStamp در عبارت WHERE تمام دستورات بروز رسانی و حذف درج خواهد شد.
- فایل IService1.cs را باز کنید و تعریف سرویس را مانند لیست زیر تغییر دهید.
[ServiceContract] public interface IService1 { [OperationContract] Payment InsertPayment(); [OperationContract] void DeletePayment(Payment payment); }
- فایل Service1.cs را باز کنید و پیاده سازی سرویس را مانند لیست زیر تغییر دهید.
public class Service1 : IService1 { public Payment InsertPayment() { using (var context = new EFRecipesEntities()) { // delete the previous test data context.Database.ExecuteSqlCommand("delete from [payments]"); context.Database.ExecuteSqlCommand("delete from [invoices]"); var payment = new Payment { Amount = 99.95M, Invoice = new Invoice { Description = "Auto Repair" } }; context.Payments.Add(payment); context.SaveChanges(); return payment; } } public void DeletePayment(Payment payment) { using (var context = new EFRecipesEntities()) { context.Entry(payment).State = EntityState.Deleted; context.SaveChanges(); } } }
- برای تست این سرویس به یک کلاینت نیاز داریم. یک پروژه جدید از نوع Console Application به راه حل جاری اضافه کنید و کد آن را مطابق لیست زیر تغییر دهید. فراموش نکنید که ارجاعی به سرویس هم اضافه کنید. روی پروژه کلاینت کلیک راست کرده و Add Service Reference را انتخاب نمایید. ممکن است پیش از آنکه بتوانید سرویس را ارجاع کنید، نیاز باشد پروژه سرویس را ابتدا اجرا کنید (کلیک راست روی پروژه سرویس و انتخاب گزینه Debug -> Start Instance).
class Program { static void Main() { var client = new Service1Client(); var payment = client.InsertPayment(); client.DeletePayment(payment); } }
شرح مثال جاری
در مثال جاری برای بروز رسانی و حذف موجودیتهای منفصل از الگویی رایج استفاده کرده ایم که در سرویسهای WCF و Web API استفاده میشود.
در کلاینت با فراخوانی متد InsertPayment یک پرداخت جدید در دیتابیس ذخیره میکنیم. این متد، موجودیت Payment ایجاد شده را باز میگرداند. موجودیتی که به کلاینت باز میگردد از DbContext منفصل (disconnected) است، در واقع در چنین وضعیتی آبجکت context ممکن است در فضای پروسس دیگری قرار داشته باشد، یا حتی روی کامپیوتر دیگری باشد.
برای حذف موجودیت Payment از متد DeletePayment استفاده میکنیم. این متد به نوبه خود با فراخوانی متد Entry روی آبجکت context و پاس دادن موجودیت پرداخت بعنوان آرگومان، موجودیت را پیدا میکند. سپس وضعیت موجودیت را به EntityState.Deleted تغییر میدهیم که این کار آبجکت را برای حذف علامت گذاری میکند. فراخوانیهای بعدی متد ()SaveChanges موجودیت را از دیتابیس حذف خواهد کرد.
آبجکت پرداختی که برای حذف به context الحاق کرده ایم تمام خاصیت هایش مقدار دهی شده اند، درست مانند هنگامی که این موجودیت به دیتابیس اضافه شده بود. اما از آنجا که از foreign key association استفاده میکنیم، تنها فیلدهای کلید موجودیت، خاصیت همزمانی (concurrency) و TimeStamp برای تولید عبارت where مناسب لازم هستند که نهایتا منجر به حذف موجودیت خواهد شد. تنها استثنا درباره این قاعده هنگامی است که موجودیت شما یک یا چند خاصیت از نوع پیچیده یا Complex Type داشته باشد. از آنجا که خاصیتهای پیچیده، اجزای ساختاری یک موجودیت محسوب میشوند نمیتوانند مقادیر null بپذیرند. یک راه حل ساده این است که هنگامی که EF مشغول ساختن عبارت SQL Delete لازم برای حذف موجودیت بر اساس کلید و خاصیت همزمانی آن است، وهله جدیدی از نوع داده پیچیده خود بسازید. اگر فیلدهای complex type را با مقادیر null رها کنید، فراخوانی متد ()SaveChanges با خطا مواجه خواهد شد.
اگر از یک independent association استفاده میکنید که در آن کثرت (multiplicity) موجودیت مربوطه یک، یا صفر به یک است، EF انتظار دارد که کلیدهای موجودیتها بدرستی مقدار دهی شوند تا بتواند عبارت where مناسب را برای دستورات بروز رسانی و حذف تولید کند. اگر در مثال جاری از یک رابطه independent association بین موجودیتهای Invoice و Payment استفاده میکردیم، لازم بود تا خاصیت پیمایشی Invoice را با وهله ای از صورت حساب مقدار دهی کنیم که خاصیت InvoiceId آن نیز بدرستی مقدار دهی شده باشد. در این صورت عبارت where نهایی شامل فیلدهای PaymentId, TimeStamp و InvoiceId خواهد بود.
نکته: هنگام پیاده سازی معماریهای n-Tier با Entity Framework، استفاده از رویکرد Foreign Key Association برای موجودیتهای مرتبط باید با ملاحظات جدی انجام شود. پیاده سازی رویکرد Independent Association مشکل است و میتواند کد شما را بسیار پیچیده کند. برای مطالعه بیشتر درباره این رویکردها و مزایا و معایب آنها به این لینک مراجعه کنید که توسط یکی از برنامه نویسان تیم EF نوشته شده است.
اگر موجودیت شما تعداد متعددی Independent Association دارد، مقدار دهی تمام آنها میتواند خسته کننده شود. رویکردی سادهتر این است که وهله مورد نظر را از دیتابیس دریافت کنید و آن را برای حذف علامت گذاری نمایید. این روش کد شما را سادهتر میکند، اما هنگامی که آبجکت را از دیتابیس دریافت میکنید EF کوئری جاری را بازنویسی میکند تا تمام روابط یک، یا صفر به یک بارگذاری شوند. مگر آنکه از گزینه NoTracking روی context خود استفاده کنید. اگر در مثال جاری رویکرد Independent Association را پیاده سازی کرده بودیم، هنگامی که موجودیت Payment را از دیتابیس دریافت میکنیم (قبل از علامت گذاری برای حذف) EF یک Object state entry برای موجودیت پرداخت و یک Relationship entry برای رابطه بین Payment و Invoice میساخت. سپس وقتی که موجودیت پرداخت را برای حذف علامت گذاری میکنیم، EF رابطه بین پرداخت و صورت حساب را هم برای حذف علامت گذاری میکند. در اینجا عبارت where تولید شده مانند قبل، شامل فیلدهای PaymentId, TimeStamp و InvoiceId خواهد بود.
یک گزینه دیگر برای حذف موجودیتها در Independent Associations این است که تمام موجودیتهای مرتبط را مشخصا بارگذاری کنیم (eager loading) و کل Object graph را برای حذف به سرویس WCF یا Web API بفرستیم. در مثال جاری میتوانستیم موجودیت صورتحساب مرتبط با موجودیت پرداخت را مشخصا بارگذاری کنیم. اگر میخواستیم موجودیت Payment را حذف کنیم، میتوانستیم کل گراف را که شامل هر دو موجودیت میشود به سرویس ارسال کنیم. اما هنگام استفاده از چنین روشی باید بسیار دقت کنید، چرا که این رویکرد پهنای باند بیشتری مصرف میکند و زمان پردازش بیشتری هم برای مرتب سازی (serialization) صرف میکند. بنابراین هزینه این رویکرد نسبت به سادگی کدی که بدست میآید به مراتب بیشتر است.
نداشتن Relation بین موجودیت Comment و User
- قسمت پروژهها فقط مرتبط هست به مشکلات پروژهها و هیچ هدف دیگری ندارد. لطفا رعایت کنید.
عدم رعایت این مساله در آینده، سبب حذف شما از سایت خواهد شد.
سایت ما هدف تبدیل شدن به انجمن عمومی پرسش و پاسخ را ندارد. از روز اول نداشتهاست.
نیازی به تعریف خیلی از مسایل در EF نیست. به صورت خودکار آنها را میتواند تشخیص دهد. مطالب سری EF را در سایت مطالعه کنید، این مورد دقیقا بحث شدهاست.
زیرنویسهای فارسی قسمت دوم «Building Windows 8 Metro Apps in C# and XAML» را از اینجا و یا اینجا میتونید دریافت کنید.
لیست سرفصلهای قسمت دوم به شرح زیر است:
Layout 00:46:16
C# Metro applications have access to numerous XAML layout features.
This module describes those services, and shows how to use them to support Windows 8 features such as display orientation, and snap.
Introduction
Layout System
Size Properties
Alignment
Margin
Demo: Margin and Alignment
Padding
Panels
Demo: Canvas
Demo: Grid and Snap
Data-Oriented Panels
ScrollViewer
Metro Layout Conventions
Layout Change Events
Summary
در کل این قسمت هم آنچنان کاری به برنامه نویسی ندارد و به بررسی و معرفی امکانات طرحبندی XAML میپردازد؛ به علاوه یک سری قراردادهای خاص مترو و همچنین نحوهی کنار آمدن با حالت snapping ویژه ویندوز 8.
قسمت سوم مروری دارد بر کنترلهای XAML که حدودا یک هفته دیگر زیرنویسهای آن تمام خواهد شد.
لطفا اگر پس از مشاهده این سری آماده شده، اصلاحی را انجام دادید، اون رو برای اعمال در اینجا ارسال کنید. از این برنامه هم جهت ویرایش فایلها میتوان استفاده کرد.