بسم الله الرحمن الرحيم با سلام معمولا در کلاس ها در پروژه هاي چند لايه چگونه پيغام ها رو کنترل ميکنند؛ از چه نوعي ميگيرند و با اون پيغام مورد نظر رو به لايه بالايي ميفرستند. با سپاس فراوان
Printable View
بسم الله الرحمن الرحيم با سلام معمولا در کلاس ها در پروژه هاي چند لايه چگونه پيغام ها رو کنترل ميکنند؛ از چه نوعي ميگيرند و با اون پيغام مورد نظر رو به لايه بالايي ميفرستند. با سپاس فراوان
سلام
سوال و نکته سنجی بسیار بجایی است.
باید به مفهوم لایه ها دقت کرد و نباید هرکجا خواستیم هر کاری انجام دهیم و فقط از لایه بندی اسمش بماند ...
(گرچه افسوس این دقت نظرها در جامعه حرفه ای ما خیلی خریداری ندارد ...)
روش های گوناگون و بسیار خوب و مطمئنی وجود دارد.
- پیام ها و ارتباطات قابل انتقال به اول کد:
از این جمله میتوان به انجام اعتبار سنجی های UI قبل از ارسال به لایه پایین اشاره کرد یا مواردئی که کاربر باید بین چند حالت انتخابی داشته باشد و...
این ساده ترین موردی است که حتماً به آن فکر کرده اید...
مثلاً ...
برای پرسش اطمینان حذف یک مورد می توان در همان لایه UI انجام شود و سپس متد اصلی لایه های پایین تر اجرا شود.
یا در حالتی که با چند وضعیت مختلف روبرو هستیم میتوان Enum ای در لایه پایین تعریف کرد که مقدار آن از بالاترین لایه UI اخذ و ارسال شود...
که State از پرسش ها و ارتباطات مختلف اولیه UI پر خواهد شد.کد:public enum State
{
None = 0,
State1,
State2,
State3
}
public void Func1(string arg1, int arg2, ... , State flags)
{
//...
}
ولی باید دقت داشت که در این کار افراط نشود.
چون تعریف enum منجر به استفاده از swith case خواهد شد و این میتواند دشمنی با پلی مورفیزم تعبیر شود ! که اصلا خوب نیست.
در حالت حداقلی (نه switch case و نه polymorphism) شاید بتوان چند متد برای هر کدام از این امور داشت که موجب تولید متدهایی با کدهای کمتر میشود.
(همواره تلاش کنید متدهای با کدهای حجیم و طولانی را به قطعات کوچکتر خرد کنید)
در خصوص روش های جالب تر دیگر در روزهای آتی خواهم نوشت ...
بسم الله الرحمن الرحيم با سلام از اينکه پاسخ داديد سپاسگزارم. لطفا براي روشن تر شدن مطلب مثالي از مقدار دهي State در لايه هاي UIو مياني بياوريد. با سپاس فراوان
بسم الله الرحمن الرحيم با سلام منظورتون اينه که مثلا لايه UI بعد از اينکه متدي از لايه مياني رو فراخواني کرد مقدار state رو بررسي کنه و اگه state=0 بود آنگاه پيغام بده که بر فرض مثال عمليات با موفقيت انجام نشد. با صحيح بودن فرض بالا مگر نبايد هر لايه اطلاعي از جزئيات لايه پاييني نداشته باشد و تنها از اون استفاده کنه؟ منظورتون رو از جمله "پیام ها و ارتباطات قابل انتقال به اول کد:" متوجه نشدم. با سپاس فراوان
سلام....
من هم نگرفتم که چی شد و البته یه چیز جالب برام پیش اومد که میخوام بپرسم در ادامه.....
کاری که من میکنم اینه که اول همهی چیزایی که تو رابط کاربر میشه بررسی کرد رو بررسی میکنم و بعد پارامتر ها رو به تابع در لایهی پایین تری میفرستم...(که همون لایهی لاجیکالم در خود برنامه باشه؟!) و بعد کلاس ها و کدهای اون قسمت، پارامتر هایی نهایی رو برای رابطم با دیتابیس میفرستن که جدیدا دیگه سرویس هایی روی وب میباشه!!! نمیدونم چقدر درسته...
این مثال اینام که زده شد، برای من یه شبهه ایجاد کرد....
ایا من میتونم مقادیر چند باکس مختلف(تکست، رادیو و چک باکس و ...!!) رو داخل اینام ذخیره کنم و بعد از اینها برای کوری گرفتن استفاده کنم؟! مثلا من 12 تا تکست باکس دارم که همه دسته بندی شدن و من میخوام کاربر هرچقدر از اینها رو بیشتر وارد کرد، جستوجوش دقیق تر باشه و خوب، هرچی کمتر بود یه جستوجوی کلی تر بگیره....؟!!! نمیدونم اگر تونسته باشم منظورم رو درست بفهونم؟!!!
در این روش باید از چی استفاده کرد؟! و ایا اصولا در بحث این سواله یا نه؟!!
سلام
نقل قول:
مثالي از مقدار دهي ... در لايه هاي UIو مياني بياوريد
شما میتوانید یکسری فرآیند های تصمیم گیری را با enum ها کنترل کنید.نقل قول:
من هم نگرفتم که چی شد
در واقع برای به دو سبک شمارشی یا بیتی میتوان از یک enum استفاده کرد و کمبود های یک bool را جبران کرد.
شمارشی برای حالتی که بیشتر دو حالت true/false نیاز باشد که در نهایت موجب استفاده از switch case در جایی از کد میشود.
و
بیتی برای حالتی که بیش از یک bool نیاز باشد
یعنی کد اول بجای کد دوم:
کد:public enum Enum1
{
None = 0,
Flag1 = 1,
Flag2 = 2,
Flag3 = 4,
}
public void Func1(... Enum1 flags)
{
if ((flags & Enum1.Flag1) > 0)
{
//...
if ((flags & Enum1.Flag2) > 0)
{
//...
}
}
//...
if ((flags & Enum1.Flag3) > 0)
{
//...
}
//...
}
==============کد:public void Func1(... bool f1, bool f2, bool f3)
{
if (f1)
{
//...
if (f2)
{
//...
}
}
//...
if (f3)
{
//...
}
//...
}
مثال عملی:
در برنامه های حسابداری قالباً لازم میشود همراه ثبت یک "فاکتور" یک "سند حسابداری" هم صادر شود...
گرچه راه حل های متفاوتی وجود دارد ولی شاید پیمانکار یا کارفرمائی ترجیح بدهد طی MessgageBox ای این مورد پرسیده شود...
در واقع بجای آنکه درون لایه پایینی این پرسش انجام شود، قبل از آن در لایه بالا پرسیده شده و نتیجه تصمیم به لایه پایین ارسال شده تا لایه پایین دیگر نیازی به تعامل با کاربر نداشته باشد.کد:bool register_accdoc = MessageBox(...?)
DownLayer.RegisterInvoice(....,...,..., register_accdoc)
تا اینجا درست!
حالا فرض کنید می خواهیم در خصوص صدور "قبض انبار" هم بپرسیم.
یعنی میخواهیم بدانیم با "صدور فاکتور" باید "سند حسابداری" یا "قبض انبار" هم (جداگانه) صادر شود یا خیر؟
اینجا دیگر نمیتوان یک bool به لایه پایین تحویل داد، اینجا دو bool یا یک enum لازم است.
یعنی میتوان یک MessgaeBox سفارشی با دو CheckBox ساخت که دو مورد فوق را پرسید و نتیجه را در یک enum به لایه پایین پاس داد.
==============
البته ...
این فقط یک مثال برای نحوه کاربرد بود.
وگرنه همانطور که بیان شد مثال فوق و هر مثال دیگری راه حل های متفاوتی میتواند داشته باشد.
از جمله در تنظیمات سراسری برنامه بله/خیر آن مشخص گردد
یا
پس از ثبت فاکتور دکمه ای برای "ثبت سند" و "ثبت قبض" ظاهر گردد و...
یا
عملیات "ثبت سند" و "ثبت قبض" دو متد مستقل باشند که از همان لایه UI فراخوانی شوند
و...
ولی تمام این روش ها تغییری در مفهوم اولیه بیان شده ایجاد نمیکند.
در واقع هدف از بیان enum آن بودکه می میتوانیم کمبودهای bool را با enum جبران کنیم و فکر خودمان را در حصار bool (دوحالته) محدود نکنیم.
روش اول: پرسش اولیه برخی موارد و ارسال به لایه پایین تا لایه پایین تعامل با کاربر نخواهد.
==============
چند مورد دیگر را برای یک تنفس کوتاه(!) و تفکیک بهتر مطالب در پست بعدی پاسخ میدهم ...
سلام
بله همه این موارد درست است...نقل قول:
نوشته شده توسط senaps
این مورد هم مشابه مورد قبلی بیان شده شما، همه و همه حالتی هستند که میتوان در اول کد فراخوانی لایه پایین تعبیه کردنقل قول:
نوشته شده توسط senaps
(((ولی مواردی پیش خواهد آمد که نمیتوان در اول (یا آخر) کد فراخانی لایه پایین کار را تمام کرد.)))
البته طبیعتاً (و همانطور که حتماً بهتر مطلع هستید) اگر بخواهید چندین مقدار شامل string, Datetime, int و... و... را به لایه پایین پاس دهید میتوانید و (شاید بهتر است) از یک class یا struct کمکی استفاده کنید....
در حالت حداقل حداقل یک ظرفی شبیه این میتوانید داشته باشید.
البته شاید...کد:public class|struct Container1
{
public int ID;
public string Field1;
public string Field2;
public bool Field3;
...
}
بتوانید از کلاس های پیش ساخته لایه "دیتابیس" هم صرفاً برای انتقال استفاده کنند.
مخصوصاً موارد تولیدی ADO.Net Entity Framework بسیار مناسب تر هستند.
فوقش برای لایه بندی بیشتر و نیز افزودن امکانات میتوانید از کلاس هاس سطرهای جداول در لایه های بالا وراثت بگیرید
و...
تا حدودی!نقل قول:
نوشته شده توسط shotok
این مورد بیان شده شما میشود، "پیام ها و ارتباطات قابل انتقال به آخر کد"
- پیام ها و ارتباطات قابل انتقال به آخر کد
یعنی میتوان یکسری از پیام ها مانند نتیجه عملیات که خودتان اشاره کردید را به آخر فراخوانی کد در UI واگذار کرد که روش های آن خیلی شبیه مورد بیان شده قبلی است.
میتوان در یک bool دوحالته یا یک enum چند حالته نتیجه عملیات را به لایه بالاسری برگرداند تا لایه بالا سری در خصوص چشم پوشی یا اطلاع رسانی مناسب به کاربر تصمیم بگیرد.
یعنی UI هایی که میتوان نشان دادن آنها را قبل از فراخوانی کد لایه پایین انجام داد...نقل قول:
نوشته شده توسط shotok
نوع دیگر میشود نمایش UI هایی پس از اجرای عملیات لایه پایین، مانند آنچه خودتان اشاره کردید و به موفق/ناموفق بودن عملیات اشاره داشت.
در نهایت شاید لازم باشد لایه پایین در حین کار برای مواردی با کاربر تعامل داشته باشد ... مانند گزارشات و خطاها و درصد پیشرفت ... لغو و توقف عملیات در جریان ... و... که به سه چهار روش مختلف در این راستا در روزهای آتی میپردازیم.
(انشاا... حداقل سه روش انتقال مختلف را بیان میکنم)
==============
عیدتان مبارک و شب خوش.
بسم الله الرحمن الرحيم با سلام از جناب _H2_ بخاطر مطلب مفيدشون تشکر ميکنم؛ سوالي از خدمتتون دارم و اون اينکه تا چه حد اين موضوع به نظر و سليقه فرد بستگي داره و تا چه حد اصول دخيل هستند؟ لطفا مقاله يا پياده سازي هايي که در اين باره انجام شده و مورد تائيد شما مي باشد رو مطرح بفرمائيد تا مطالعه بيشتري راجع به اين موضوع داشته باشيم. با تشکر فراوان از وقتي که ميگذاريد.
سلام
انتقال استثناها:
چیزی که ما معمولاً با نام خطا در برنامه میشناسیم در واقع یک مکانیزم انتقال اطلاعات بین لایه های مختلف است.
که با هوشمندی زیبا در دات نت به جای کلمه Error به آن کلمه وسیع تر Exception را داده اند.
این شیوه انتقال در مواردی استفاده میشود که لایه پایین به دلیلی نتواند کارش را به درستی انجام دهد و بخواهد این مسئله و دلایل آن را به لایه بالاسری اطلاع دهد.
ابتدا اجازه دهید یک شیوه دیگر برخورد با این مسئله را بررسی کنیم تا از مشکلات و ایرادات آن روش، محاسن و جذابیت های روش Exception را بهتر درک کنیم. تا کمتر از آن بترسیم! و به آن به چشم یک ناجی و امکان بسیار کارآمد و مطمئن پی ببریم.
پس میخواهیم راه حل کاملی پیدا کنیم تا اگر متدی در لایه پایین به دلایلی نتوانست کارش را صحیح انجام دهد بتواند آن را به لایه بالا اعلان کند و لایه بالا هم بتواند خودش به تصمیم خودش و شیوه مناسب آن را به کاربر اعلان کند یا نکند.
دقت کنید که لایه آخر میتواند یک WinForm, WpfForm, ... WinService, WebService, ... XNA, ... WebSite و... باشد که فقط و فقط لایه آخر میداند چطور باید پیغام مناسب را نمایش دهد.
ضمن اینکه این مفهوم میتواند بین لایه های میانی (غیر آخر و UI) هم کاربرد داشته باشد.
=====
روش ناقص و مشکل دار:
در ساده ترین دید تشکیل یک enum میدهم
خوب مشکل من را که حل کرد! پس چه ایرادی دارد؟!کد:public enum Func1Result
{
succeeded = 0,
Error_Name1,
Error_Name2,
Error_Name3,
...
}
//Layer1
public Func1Result Func1(....)
{
...
... if (...) return Func1Result.Error_Name2;
...
}
//Layer2
...
var result = Func1(...);
switch(result)
{
case Func1Result.Error_Name1:
//e.g. MSGBOX(TEXT1)
case Func1Result.Error_Name2:
//e.g. MSGBOX(TEXT2)
case Func1Result.Error_Name3:
//e.g. MSGBOX(TEXT3)
}
1) switch case عریض و طویل همیشه از منظر دید شی گرایی مطرود و بد است و باید شیوه های مناسب شی گرایی تعویض شود.
2) اگر Func1 خودش مقدار بازگشتی داشته باشد چه؟
بله میدانم که حداقل سه راه متفاوت میتوان بیان کرد، ولی قبول دارید هر سه راه کمی قشنگ نیستند و مناسب لفظ کثیف کاری هستند؟!
3) اگر Func1 خودش چند تابع دیگر را اجرا کند که هر کدام هم یک سری خطای عریض و طویل مخصوص خود را داشته باشند چه؟
آنگاه حتماً باید enum نتیجه خروجی Func1 شامل جمیع enum های توابعی که صدا کرده باشد؟؟؟!
افتضاح زمانی بالا میگیرید که آن چند تابع هم خودشان توابع دیگری را اجرا کنند...!
و حتماً بعدش هم با تغییر کدهای داخل یک تابع باید enum آن و کلیه enum های توابع بالاسری را اصلاح کنم ... ! چه شود ... !
پیشنهاد میکنم مطمئن شوید که این بند (3) را حداقل متوجه شده اید!
4) اگر یک خطا اطلاعات اضافه داشته باشد چه؟
مثلاً "فاکتور فروش" در سیستم ثبت نشده چون "یک کالای خاص" در فهرست فاکتور، موجودی اش در انبار "صفر" بوده.
خوب نمیخواهید به کاربر بگویید "کدام کالا" بوده؟
پس در یک دید کلی باید بتوان همراه یک خطا اطلاعات اضافه هم به لایه بالاتر ارسال کرد.
و...
هر روشی (غیر از Exception) که پیشنهاد کنید مشکلات این تیپی را خواهد داشت.
با تنفسی کوتاه در ساعت آتی مطلب را ادامه خواهیم داد...
سلام
ادامه مطالب ...
روش صحیح: (Exception)
Exception ها راه حلی بر مبنای اصول شی گرایی برای برخورد با مسئله فوق الذکر هستند.
بدلیل فرصت کم و عدم تکرار مطالب موجود، فرض میشود دوستان مطلب زیر را قبلاً مطالعه کرده اند:
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
میدانم طولانی میشود ولی یا من باید اینجا دوباره بنویسم و شما بخوانید یا باید ارجاع بدهم و شما انجا بخوانید، در هر صورت شما باید بخوانید...!
لطفاً مطالعه شود و سپس مطالب بعدی را بخوانید.
=====
ادامه ...
پس طبق مطالب قبل متوجه شدیم Exception در واقع کلاس هایی هستند که خطاها را حمل میکنند و نیازی به تنظیم پارامتر خاصی در ورودی یا خروجی تابع ندارند.
اگر دقت کنید متوجه میشوید که این شیوه استاندارد دات نت در توابع خودش هم است.
به عنوان نمونه دستور زیر را اجرا میکنیم:
این کد میتواند از انواع پروژه های مختلف فراخوانی شود.کد:System.IO.File.WriteAllText("d:\\file.txt", "THIS IS A TEST");
ولی رویکرد WriteAllText وقوع Exception برای حالات استثنا است تا لایه فراخوان در مورد نحوه عملکرد خود تصمیم بگیرید.
دقت کنید که خیلی مهم است که در این رویکرد دیگر "کد خطا" نداریم، بجایش "کلاس استثنا" داریم.
مثلاً کد زیر میتواند استثنا های زیر را راه اندازی کند.
مثلاً با کد زیر میتوانیم در لایه بالا با این امر تعامل داشته باشیم.کد:System.ArgumentException
System.ArgumentNullException
System.IO.PathTooLongException
System.IO.DirectoryNotFoundException
System.IO.IOException
System.UnauthorizedAccessException
System.IO.FileNotFoundException
System.NotSupportedException
System.Security.SecurityException
در این رویکرد حتی میتوان تغییر زبان UI را هم به سادگی مدیریت کرد...کد:try
{
System.IO.File.WriteAllText("d:\\file.txt", "THIS IS A TEST");
MSGBOX-Win-Wpf-Web...("عملیات با موفقیت انجام شد");
}
catch(System.UnauthorizedAccessException ex)
{
MSGBOX-Win-Wpf-Web...("برنامه مجوز لازم برای دسترسی به این فایل را ندارد");
}
catch(System.NotSupportedException ex)
{
MSGBOX-Win-Wpf-Web...("مسیر فایل داده شده صحیح نمیباشد");
}
catch(Exception ex)
{
MSGBOX-Win-Wpf-Web...(ex.Message);
}
مثلاً میتوان دیکشنری از انواع کلاس های استثنا و متن نمایشی معادلشان داشت (که مثلاً از یک فایل XML پر شده باشد)
حتی میتوان خطاهای سفارشی خودمان را تولید کنیم یا خطاهای سلسه مراتبی ایجاد کنیم که به خطاهای دیگری ارجاع داشته باشد.
مثال مسخره ای از حذف تعدادی تصویر مرتبط با عدد شماره کالا
همانطورکه قبلاً هم بیان شد، در واقع این یک روش انتقال اطلاعات از لایه های پایین به سمت بالا استکد://Layer1
public class GoodsException
: Exception
{
public readonly int ID_Goods; //کد کالایی که در آن مشکلی به وجود آمد
public GoodsException(int ID_Goods, Exception innerException)
: base(innerException.Message, innerException)
{
this.ID_Goods = ID_Goods;
}
}
//Layer1
public void DeleteGoodsPicture(string directory, int[] id_goods)
{
if (string.IsNullOrEmpty(directory))
throw new ArgumentNullException("directory");
if ((id_goods == null) || (id_goods.Length <= 0))
throw new ArgumentException("باید فهرستی از فایلها انتخاب یا وارد شده باشد");
string format = System.IO.Path.Combine(directory, "{0}.jpg");
foreach (int id in id_goods)
{
try
{
System.IO.File.Delete(string.Format(format, id));
}
catch (Exception ex)
{
throw new GoodsException(id, ex);
}
}
}
//Layer2
public void Func2(string directory, int[] id_goods, ...)
{
//...
DeleteGoodsPicture(directory, id_goods);
//...
}
//Layer3
public void Func3(string directory, int[] id_goods, ...)
{
//...
Func2(directory, id_goods);
//...
}
//Layer4
public void UI()
{
try
{
Func3("D:\\pictures\\", new int[] { 5, 14, 20, 52, 110, 728 });
}
catch (GoodsException ex)
{
string message = "خطا در حذف تصویر کالا شماره {0}\r\n{1}";
message = string.Format(message, ex.ID_Goods, ex.InnerException.Message);
MSGBOX-Win-Wpf-Web...(message);
}
catch(Exception ex)
{
MSGBOX-Win-Wpf-Web...(ex.Message);
}
}
که در تولید و تسخیر کاملاً از قوانین شی گرایی تتبعیت میکند...
میتواند متن و دلیل اتفاق از داخل لایه پایین تنظیم شود و فقط لایه بالا در نحوه نمایش یا برخورد با ان تصمیم بگیرید...
میتوانید شامل اطلاعات اضافه تشریحی برای لایه بالا باشد.
به راحتی رویکرد صحیحی در فراخوانی های تو دو تو دارد و میتواند پیام های فراخوانی های لایه های پایین را از لایه های میانی انتقال دهد
و...
و...
و...
مزیت های این روش واقعاً بیشمار است و از حوصله من یکی خارج است
این روشی مطمئن برای انتقال داده است و تنها قید آن این است که موجب توقف اجرای کد در تمام متدهای فراخوان میشود.
موفق باشید.
سلام
تولید چند لایه در واقع یک روش مفهومی مهندسی نرم افزار است که هیچ کلمه کلیدی ساختار مدون قطعی ندارد.نقل قول:
نوشته شده توسط shotok
هرچه پروژه بزرگ تر باشد و ارتبطات زیادتری داشته باشد (دیتابیس،سایت، شبکه، سخت افزارخاص و سرویس های ویندوزی و وبی و...)، بیشتر به سمتی پیش میرود که افراد مختلف لایه بندی های متفاوتی تشکیل دهند و البته ایراد خاصی هم ندارد.
مهم رعایت آن تفکر اصلی است که به ایجاد گروه هایی از کلاس ها برای انجام وظیفه ای مشابه و عدم انجام کارهای متنواع در یک کلاس واحد اشاره دارد.
مانند آنکه که خودتان هم به درستی اشاره کردید که یک لایه میانی حق ارتباط گیری مستقیم با کاربر یا دیتابیس را ندارد و باید وظیفه فوق را به گروه یا لایه مربوطه محول کند.
منابع:
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
بسم الله الرحمن الرحیم
با سلام
از استاد بزرگوار جناب _H2_ نهایت تشکر رو دارم و برای ایشان و تمامی _H2_هایی که با اخلاص علمشون رو در اختیار ما قرار میدهند آرزوی توفیق و سلامت دارم.
سوالی دارم 2 رویکرد در این موضوع میتوان داشت:
1) در هر لایه ای پیغام های مخصوص به خودش رو قرار بدهیم. ایراد این روش این است که نمی توان تغییر زبان UI را مدیریت کرد.
2) پیغام را به لایه بالاترش بفرستیم و لایه بالاسری تصمیم گیری کند. ایراد روش ذکر شده این است که باید در لایه بالاتر دوباره کاری انجام شود. ( فرض بفرمائید بخواهیم با جزئیات مشخص کنیم که کدام استثنا رخ داده است.اگر استثنا1:آنگاه ... اگر استثنا2:آنگاه... و الی غیر)
و به نظر میرسد مشکلی که در مورد Enum مطرح شده بود؛ تکرار شود.
با تمام این تفاسیر کدام روش مقرون به صرفه است.نقل قول:
اگر Func1 خودش چند تابع دیگر را اجرا کند که هر کدام هم یک سری خطای عریض و طویل مخصوص خود را داشته باشند چه؟
آنگاه حتماً باید enum نتیجه خروجی Func1 شامل جمیع enum های توابعی که صدا کرده باشد؟؟؟!
افتضاح زمانی بالا میگیرید که آن چند تابع هم خودشان توابع دیگری را اجرا کنند...!
با سپاس فراوان
سلام
اول عضر خواهی میکنم چون باید اعتراف کنم که این تاپیک را کلاً فراموش کرده بودم و اگر شما تاپیک را فعال نکرده بودید معلوم نبود کی مجدد یادم بیاید... میبخشید...
دوم در مورد سوالتان ...
برای چند زبانه شما میتوانید یا از فایلهای resx خود دات نت استفاده کنید و یا یک مخزن XML ای از متون تشکیل دهید.
به دلایلی استفاده از مستقیم از فایلهای XML مقبولیت بیشتری از فایلهای resx داشته (که البته آنها هم ذاتاً XML هستند...)
هم میتوان کل این را در یک فایل واحد برای کل پروژه ذخیره کرد و هم میتوان آن را در قالب چند فایل مجزا دید، مثلاً یک فایل XML برای هر لایه و حتی یک فایل XML برای پیام های مشترک در تمام لایه ها و...
برنامه به سادگی میتواند زمان بالا آمدن تمام این فایلها در یک Dictinary بارگذاری کند که در تمام لایه ها در دسترس باشد.
این دیکشنری میتواند شامل کلیه پیام های خطا و هشدار و موفقیت و نام دکمه ها و برچسب ها و... باشد.
این فایل یا فایلهای XML هم میتواند داخل exe باشد و هم (چه بهتر) در خارج از برنامه و کنار Exe باشد.
(تا هر کسی از روی نسخه انگلیسی و بدون کمترین دانش برنامه نویسی بنواند آن را به زبان خودش ترجمه کند)
کد:public static string SR(string Key) //Reference in all layers
{
//...
//dictionary...
//...
}
//...
public class X1Exception
: Exception
{
public int a:
public string b;
//...
public X1Exception(string TextKey)
:base(SR(TextKey))
{
this.ID_Goods = ID_Goods;
}
}
//...
throw new X1Exception("ErrorBank.AccessDenied");
//...
throw new X1Exception("ErrorBank.DAL.DatabaseNotFound");
بسم الله الرحمن الرحیم
با سلام
از پاسختون بینهایت ممنون.
لطفا راجع به مطلبی هم که در مورد دیکشنری فرمودید بیشتر توضیح بدید.
متاسفانه هنوز متوجه نشدم که:
1) در هر لایه ای پیغام های مخصوص به خودش رو قرار بدهیم؟ ایراد این روش این است که نمی توان تغییر زبان UI را مدیریت کرد.
یا
2) پیغام را به لایه بالاترش بفرستیم و لایه بالاسری تصمیم گیری کند؟ ایراد روش ذکر شده این است که باید در لایه بالاتر دوباره کاری انجام شود. ( فرض بفرمائید بخواهیم با جزئیات مشخص کنیم که کدام استثنا رخ داده است.اگر استثنا1:آنگاه ... اگر استثنا2:آنگاه... و الی غیر)
و به نظر میرسد مشکلی که در مورد Enum مطرح شده بود؛ تکرار شود.
می بخشید دوباره سوالم رو تکرار کردم.
با سپاس فراوان
سلام
انشاا... فرصت کنم، تلاش میکنم امروز و فردا به جای تایپ مطلب بعدی یک نمونه پروژه فوق العاده ساده چند لایه حاضر کنم که مورد ترجمه مدنظر شما را داشته باشد.
شاید مشاهده این پروژه، ساده تر از توضیح دادن باشد.
سلام
میبخشید دیر شد طبق معمول مشکلات الوان تمامی ندارد...
یک نمونه فوق العاده بچه گانه درست کردم...
خیلی ساده است و خیلی از اصول عالی را رعایت نکرده است.
ولی نمونه مخزن متن های xml و خطای چند زبانه را دارد.
کد خیلی خیلی کم بیش از ترجمه xml ای صرف دیده شده و چند کلاس و اینترفیس اضافه برای کمی نزدیک شدن به پروژه های واقعی را هم دارد...
برای ترجمه و آرشیو xml از یک dll از خودم استفاده کردم تا سرعت تولید را کاهش دهم ...
دوستان میتوانند خودشان یک فهرست و مفسر xml به پروژه اضافه کنند...
در پروژه جاری فایل های ترجمه در قالب فایل xml جداگانه و در پوشه Localization در بیرون برنامه قرار دارد.
برنامه قابلیت ادغام xml ها را دارد به این معنی که میتوان یک xml را به چند فایل xml بشکنید، برنامه خودکار زمان بالا امدن همه آنا را به نوعی در حافظه merge میکند.
کلید ادغام عدد فرهنگ زبان LCID است.
مثلاً فایل زیر:
میتواند به دو فایل مستقل زیر شکسته شود.کد:<?xml version="1.0" encoding="utf-8" ?>
<doc>
<Group Key="MessageBox.Title">
<Item Key="Error" >خطا</Item>
<Item Key="Question" >سوال</Item>
<Item Key="Warning" >هشدار</Item>
<Item Key="Information" >نتیجه</Item>
</Group>
</doc>
وکد:<?xml version="1.0" encoding="utf-8" ?>
<doc>
<Group Key="MessageBox.Title">
<Item Key="Error" >خطا</Item>
<Item Key="Question" >سوال</Item>
</Group>
</doc>
کد:<?xml version="1.0" encoding="utf-8" ?>
<doc>
<Group Key="MessageBox.Title">
<Item Key="Warning" >هشدار</Item>
<Item Key="Information" >نتیجه</Item>
</Group>
</doc>
در نتیجه انتخاب آنها متن های هر لایه یا گروه یا فرم یا بخش و... در یک فایل xml مستقل باشد یا اینکه کل پروزه یک فایل xml واحد داشته باشد به عهده خودتان است و نیاز به تغییر یک خط از کدها هم ندارد.
دقت کنید در محیط VS (به دلیل ریست تنظیمات) شاید combobox ای که زبان برنامه را تغییر میدهد شاید دفعه اول کار نکند ولی اگر نمونه exe را مستقیماً اجرا کنید متوجه میشوید مشکلی وجود ندارد.
بررسی کنید مشکلی بود روی معیار همین پروژه بحث میکنیم.
با کمی تغییرات امکان ذخیره xml ها درون خود dll ها و exe ها هم وجود دارد.
[ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
موفق باشید.
بسم الله الرحمن الرحیم
با سلام
قبل از هر چیز از اینکه وقت گذاشتید و نمونه برنامه رو حاضر کردید بینهایت ممنون؛ سپاسگزارم.
کل برنامه اجرا نمی شود خطای زیر رو میده.نقل قول:
دقت کنید در محیط VS (به دلیل ریست تنظیمات) شاید combobox ای که زبان برنامه را تغییر میدهد شاید دفعه اول کار نکند ولی اگر نمونه exe را مستقیماً اجرا کنید متوجه میشوید مشکلی وجود ندارد.
a project with an output type of class library cannot be started directly. in order to debug...
چون میخواهم برنامه رو خط به خط اجرا بگیرم برام مهمه که در محیط VS اجرا بگیرم ولی فایل exe به خوبی کار میکنه.
حدود یک ربع به این برنامه به قول خودتون بچه گانه زل زدم ولی کلیت کار دستم نیومد:n13:
جسارت بنده رو ببخشید ولی لطفا توضیحات بیشتری در مورد برنامه بفرمائید.
خیلی وقته که منتظر این برنامه بودم بنابراین نمی تونم به راحتی ازش بگذرم.
ببخشید که وقتون رو میگیرم.
ان شاالله تا شما جواب میدید بازهم خودم تلاش میکنم تا ابهاماتم رو مرتفع کنم.
پیشاپیش تشکر میکنم.:n16:
سلام
در solution هایی که شامل بیش از یک project هستند، فقط و فقط یک پروژه را باید به عنوان startup مشحص کنید.نقل قول:
کل برنامه اجرا نمی شود خطای زیر رو میده.
a project with an output type of class library cannot be started directly. in order to debug...
این پروژه آغاز کننده معمولاً نامش در solution explorer به صورت bold شده نشان داده میشود.
در حال حاضر دررایانه شما با این پروژه صفر کیلومتر، یکی از dll ها به عنوان startup قرار گرفته که قابل اجرا نیست.
مشابه آن است که بخواهید با دبل کلیک یک dll برنامه را اجرا کنید ... !
کافیست روی پروژه اصلی exe در solution explorer راست کلیک کنید و گزینه startup را فعال کنید.
VS این تنظیم را برای solution در قالب یک فایل مخفی جداگانه ذخیره خواهد کرد و در دفعات بعد آن را حفظ خواهد کرد.
پروژه در مسخره ترین حالت ممکن است.نقل قول:
لطفا توضیحات بیشتری در مورد برنامه بفرمائید
این را میگویم تا هم به خودتان مطمئن تر شوید و هم چون به قطع در آینده بدلیل عدم رعایت مستحکم تر برخی اصول به جاهایی از این پروژه خواهید خندید...
4 پروزه داریم...
PublicLibrary به عنوان کتابخانه عمومی است که به تمام لایه های دیگر سرویس های خلی کلی و عمومی را ارائه میدهد...
مثلاً میتواند شامل تعریف خالی بدنه interface ها باشد...
میتواند شامل تعریف کلاس های static حاوی توابع عمومی باشد ... توابه کمکی LINQ ... توابع کمکی ریاضی مثل factorial ... توابع محاسباتی ... توابع پردازش string ... و..و...و...
وجود این لایه در معماری سرویس گرایی خیلی مهم تر خواهد شد...
DatabaseLayer
لایه دیتابیس که فعلاً بجز به جریان انداختن یک Exception چند زبانه کار دیگری انجام نمیدهد.
KernelLayer
لایه هسته مرکزی که فرض شده ماژول ها و سرویس های مختلفی را زمان بالا آمدن برنامه به جریان خواهد انداخت...
بطرز خیلی بچه گانه ای کلاس ساده Kernel.Application ، معرف بارگذاری این لایه و کلاس اصلی آن است که مسئول بارگذاری سایر خدمات این لایه است، همچنین در صورت لزوم نابود سازی این خدمات در زمان بسته شدن برنامه برعهده دارد...
در یک طراحی عالی میتوان کاری کرد که ضمن انجام اکثر پردازش های برنامه در این لایه، ولی تمام کلاس های این لایه به صورت خصوصی باشند و کلاً خارج از دسترس مستقیم تمام لایه های دیگر باشد و نیازی هم به فراخانی مستقیم انها از لایه های دیگر نباشد .... شاید الآن کمی گفته هایم نا معقول بنظر برسد ولی به آن فکر کنید ... ... ... ...
کلاس StringResourceModule در این لایه مسئول اصلی بارگذاری xml های زبان است که برای این کار کمی از پارسر و دیکشنری داخل ghdiamond کمک گرفته ...
توجه کنید که به عنوان مثال به جای new کردن مستقیم این کلاس در لایه exe .... آمده ام و در لایه exe کلاس اصلی Kernel.Application را نمونه سازی کرده ایم و این کلاس آمده و کل مکانیزم هالی موجود در لایه kernel را برای ما در حافظه بارگذاری کرده که از البته فعلاً فقط کلاس StringResourceModule ...
در یک پروژه کامل ، هر لایه میتواند شامل کلاسی مشابه Kernel.Application جهت مدیریت لایه و فرمان بارگذاری و نابود سازی اشیای لایه باشد و میتوان تمام هزینه زمانی بازگذاری ماژول های این لایه ها را به پشت پنجره SplashScreen منتقل کرد و حتی گزارش بارگذاری ماژول ها هم روی SplashScreen نشان داد ...
UILayer
یک پروژه winform در ساده ترین حالت ممکن است...
شاید مهم ترین تابع این بخش، (تابع خیلی ناقص و مشکل دار) Transfer باشد که در یک حالت حداقلی وظیفه ترجمه اشیای روی فرم (جالب تر انکه هر کنترلی) را بر عهده دارد.
در پست قبلی نمونه xml را دیدید و متوجه شدید که نمونه xml پیشنهادی من دو سطحی است که یک gkey گروه دارد و هر گروه میتواند چندین جزء با skey دیگری داشته باشد.
تابع Transfer هم gkey یک گروه را میگیرد و در ان گروه Text کنترلها را به عنوان skey جزء استفاده میکند...
کد:<?xml version="1.0" encoding="utf-8" ?>
<doc>
<Group Key="gkey1">
<Item Key="skey1" >Text1</Item>
<Item Key="skey2" >Text2</Item>
<Item Key="skey3" >Text3</Item>
...
</Group>
<Group Key="gkey2">
<Item Key="skey1" >Text1</Item>
<Item Key="skey2" >Text2</Item>
<Item Key="skey3" >Text3</Item>
</Group>
...
</doc>
کد را از داخل vs اجرا و دنبال کنید، متوجه میشوید...
موفق باشید.
سلام..... من یه سوال برام پیش اومد و اون اینکه من همیشه کل دیتام رو میگیرم و میارم به لایهی نمایش و تمام.... حالا الان که دارم با سرویس ها کار میکنم، راستش فکر میکنم که بهینه ترین حالت ممکن اینه که دیتای خام رو از سرور و سرویس بگیرم و تو کلاینتم روش کار کنم........................اگر تو ویندوز 7 چیزی رو سرچ کنین، مثلا یه جستجوی اینفینت که همهی فایل ها رو نشون بده، به حالتی نمایش میده که فقط اسمشون رو داری، بعد اگه حالت نمایش رو بذاری روی دیتیل، دوباره میره تو سرچ و طول میکشه!!! این اتفاقیه که الان برا من و برنامههای کلاینتم میافته.... چون کلاینت فقط نمایش میده و میره دیتاش رو از سرویس میگیره!!!!............اگر مثلا کاربرم بخواد فیلدی رو از گرید حذف بکنه یا نمایش بده، یا نوع سورت دیتا رو عوض بکنه، باید اطلاعات به اون شکل دوباره دریافت بشن!!! راه حل این مسئله چیه؟!
سلام علیکم،
شما خیلی ساده میتوانید از مکانیزم های Cache و Paging استفاده کنید.
Paging با کاهش حجم دریافت اطلاعات سرعت انتقال و بازدهی برنامه را افزایش میدهد و در نهایت به پهنای باند شبکه هم کمک میکند
و
Cache هم با عدم درخواست مجدد همین نتایج را در بر دارد.
برای مرتب سازی و برخی موارد ف-ی-ل-ت-ر سریع (غربال در حین تایپ کیبورد) میتوان در مکانیزم های FX4-Typed از Linq و در سایر موارد از کامپونت هایی مانند BindingSorurce استفاده کرد
((
مثلاً در لیست های بازشویی از جداول افراد، کالاها و خدمات و... و...میتوان مکانیزم های کاملی پیاده سازی کرد که در حین تایپ کاربر امکان غربال اطلاعات را بر اساس کد و نام و ... فراهم کند...
در این موارد که به نوعی جستجوی سریع است نمیتوان با تایپ هر کاراکتر یک دستور SQL جدید را اجرا نمود
))
البته در مورد کش باید به حجم لازم RAM و میزان تغییر اطلاعات هم دقت کنید
مواردی که خیلی کم تغییر میکنند و خیلی زیاد استفاده میشوند و حجم کمی دارند برای کش بسیار ایده آل هستند.
بطور مثال در یک برنامه خرید و فروش "گروه های کالا" یا " واحدهای شمارش کالا" یا در مقیاس تجاری بزرگتر "فهرست انبارها" و... گزینه های خوبی برای کش هستند تا کل لیست های بازشو برنامه را تغذیه کنند.
در مبنای پیشرفته تر میتوانید یک ماژول مرکزی کش داشته باشید که با یک کلید (مثلاً string ای شامل نام دلخواه با ترکیب نام جدول دیتابیس و...) داشته باشید که ضمن کش اطلاعات بتواند زمان انقضایی برای آنها هم در نظر گرفته و بعد گذشت این زمان اطلاعات را حذف کند... چیزی شبیه ماژول مشابه اش در ASP.Net ....
برای بارگذاری اطلاعات هم میتوان از تکنیک Lazy استفاده کرد و تا زمان اولین درخواست بعدی این کار را به عقب انداخت ...
=====
این کارها بدون شک به کدنویسی نیاز دارد و سادگی یک DataAdapter.Fill را ندارد ولی دقت به این جزئیات که شما گفتید و تولید برنامه خوب بدون کدنویسی نمیشود
مورد اول انکه شما میتوانی مجموعه ای از کلاس ها و کامپونت ها برای خودتان ایجاد کنید که برای هر پروژه و هر کار نیازی به دوباره کاری نداشته باشید.
یعنی وقتی به یک مکانیزم نیاز دارید با دید وسیع تری آن را طوری طراحی و کدنویسی کنید که برای پروژه های بعدی هم قابل استفاده باشد.
همین مفهوم لایه بندی / پلاگین پذیری / DLL / OOP و... اگر درست انجام شود به تولید کدهای "قابل استفاده مجدد" (یکی از اصول پایه برنامه نویسی) کمک میکند.
و مطلب دوم هم آنکه اگر به هر جزء به طور تکی نگاه کنید، متوجه میشود، خیلی هم پیچیده و مشکل نیست، شاید کمی کدبخواهد ولی کد سختی نیست و الگوریتم های پیچیده ریاضی ندارد.
حالا نمیدانم از مطالب فوق بطور دقیق با پیاده سازی کدام بخشش مشکل دارید؟!
====
گمانم باید بقیه مطالبی که قولش را داده بودم تایپ کنم...
بابت طولانی شدن انشاا... خواهید بخشید...
موفق باشید.
بسیار ممنون....
از همون نیاز به کش کردن میترسیدم!!
دوبار تو برنامههام ازش استفاده کردم پشت دستم رو داغ کردم که تا تسلط کافی دیگه دیتابیس رو کش نکنم :n02:
ولی این صفحهبندی رو نفهمیدم کاربردش دقیقا چی بود(غیر از خود صفحهبندی!!)....
به هر صورت، بسیار ممنون دوست گرامی ایدهی خوبی دادید.... و به ظاهر، باید برم تو کار همون نوشتن یه سری dll....(اخرش کارم به اونجا میرسه که یه کتابخونهی گنده مثل داتنت داشته باشم!! خودم میدونم:n09: )
به شدت منتظر ادامهی مطالبتون در این تاپیک هستم....
بسم الله الرحمن الرحیم
با سلام
بینهایت از پاسخ جناب _H2_ سپاسگزارم.:n16:
با اجازه ایشون پاسخ کوتاهی خدمت [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ] عرض میکنم.
یه نمونه کد که قبلا برای نمایش فاکتورها در برنامم ازش استفاده کردم براتون میگذارم تا ان شاالله مشکلتون مرتفع بشه. اصلا چیز خاصی نداره یه سرچ بزنید کلی نمونه پیدا میکنید.نقل قول:
ولی این صفحهبندی رو نفهمیدم کاربردش دقیقا چی بود(غیر از خود صفحهبندی!!)....
کد:SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[SPViewFactors]
@FactorCode bigint=0, --Show Factor with spesial FactorCode.
@FromDate datetime=null, --show Factors of spesial Date.
@ToDate datetime=null,
@PageNumber bigint --Implicity Paging In DataBase
AS
BEGIN
--Count of Records In The Each Page In Paging.
DECLARE @PageSize smallint
SET @PageSize=14
SET NOCOUNT ON;
SELECT *
FROM (
--Implicity Paging
SELECT ROW_NUMBER() OVER (ORDER BY FactorCode)AS RowNum,
FactorCode, Date,
Description,
StoreCode
FROM Factor
WHERE
/*@FactorCode is Optional Parameter*/
(@FactorCode =0 OR FactorCode=@FactorCode)
/*@FromDate AND @ToDate are Optionals Parameter*/
AND (@FromDate is null OR (Date BETWEEN @FromDate AND @ToDate)))Result
WHERE
--Implicity Paging
(RowNum>@PageSize *(@pageNumber - 1)AND RowNum <=(@PageSize * @pageNumber))
END
متاسفانه نتونستم برای صفحه بندی این کار رو انجام بدم و حالت کلی در نظر بگیرم.نقل قول:
یعنی وقتی به یک مکانیزم نیاز دارید با دید وسیع تری آن را طوری طراحی و کدنویسی کنید که برای پروژه های بعدی هم قابل استفاده باشد.
همین مفهوم لایه بندی / پلاگین پذیری / DLL / OOP و... اگر درست انجام شود به تولید کدهای "قابل استفاده مجدد" (یکی از اصول پایه برنامه نویسی) کمک میکند.
موفق باشید.
گمانم منظورتان نحوه صفحه بندی و چگونگی ان نباشد.نقل قول:
ولی این صفحهبندی رو نفهمیدم کاربردش دقیقا چی بود
من چنین برداشت میکنم که منظورتان چرایی آن است. اینکه که چه ربطی به بحث داشت؟ و چه لزومی دارد؟
اگر چنین است...
هدف نهایی آن است که فرمان کاربر در حداقل زمان ممکن انجام شود.
در واقع گمانم روی این توافق داشته باشیم که چکیده پست 19 شما نگرانی در خصوص بازدهی زمانی باشد.
=====
مثال: کاربر میخواهید Sort اطلاعات را براساس یک ستون تغییر دهد ...
بالاخره یک جایی یک کدی باید این Sort مجدد را انجام دهد، این کاری است که بحرحال باید انجام شود، الگوریتم های Sort هم مشخص است، حالا یا SQLServer یا LINQ یا BindingSorurce و...
بطور دقیق چه چیز باعث تفاوت سرعت پاسخ به کاربر خواهد شد؟!
الگوریتم Sort که مشخص است و فقط کدهای مختلف آن را انجام میدهند نباید اینقدر تفاوت ایجاد کند.
تفاوت بازدهی در نحوه دسترسی به اطلاعات و انتقال آنها وجود دارد که خود را نشان میدهد.
یعنی اگر میشد، پارامتر تاثیرگذار فوق را حذف کرد، شاید همه سه روش فوق در سرعت یکسانی این کار را انجام میداند.
پس در واقع گلوگاه مشکل "دسترسی و انتقال" اطلاعات است.
دقت کنید که وقتی از انتقال اطلاعات صحبت میکنیم این شامل
- سریالی کردن اطلاعات در برنامه سرور
- ارسال اطلاعات (بطور معمول تحت پروتکل TCP/IP) از هفت لایه شبکه
- دریافت اطلاعات از هفت لایه شبکه
- سرانجام دی-سریالی اطلاعات در برنامه کلاینت
است.
به عملیات های فوق باید ظرفیت انتقال و ترافیک شبکه را هم اضافه کرد، اغلب شبکه های داخلی شرکت های ما حدود 10MByte/S ظرفیت انتقال دارند. (که البته کافی است)
یعنی وقتی سروری با یک کارت/کابل شبکه معمولی به سوییچری متصل است و همزمان 10 کلاینت درخواستی میدهند، حداکثر با سرعت 1MByte/S میتواند پاسخ هر یک را بدهد و...
اگر روی همین سرور ISA/IIS/SQLServer و... هم نصب باشد، این عدد بین دسترسی به اینترنت و شبکه داخلی و بانک اطلاعاتی و... تقسیم خواهد شد.
((شاید بارها مشاهده کرده باشید که در شبکه های عادی شرکتی وقتی کسی فایل سنگینی دانلود میکند، حتی یک سایت معمولی برای دیگران به سختی باز میشود))
البته لزومی ندارد خیلی نگران شوید!
بر میگردیم سر بحث اصلی ...
Cache با عدم انتقال مجدد اطلاعات و در دسترس نگاه داشتن آنها (در شرایط استفاده صحیح) میتواند بازدهی سرعتی را افزایش دهد.
چون بطور خلاصه کمتر از ترافیک شبکه استفاده میکند، ضمن اینکه با عدم اشغال شدن پهنای باند شبکه در سرعت سایر کلاینت ها هم تاثیر خواهد داشت.
Paging هم با انتقال کمتر اطلاعات میتواند بازدهی سرعتی را افزایش دهد.
و همان ترتیب ترافیک شبکه را کمتر اشغال کند و در سرعت عمومی کل شبکه و حتی سایر کلاینت ها کمک کند.
(((
شرکت مان برای پروژه ای با یک بخش دولتی در حال مذاکره بودیم که یکی از جداول آنها نزدیک 100 میلیون رکورد داشت...
البته سرورهای خوبی داشتند و مشکل RAM و CPU و... اصلاً نداشتند و آخر هم سر قیمت به توافق نرسیدیم ...
بیخیال 100 میلیون...
شما نمیتوانید یعنی منطقی نیست که 20000 رکورد را یکباره دانلود کنید و به کاربر نشان دهید، این کار حافظه و پردازش گر و شبکه را بسیار درگیر میکند و زمان پاسخ دهی برنامه تان بسیار کند خواهد کرد.
)))
موفق باشید.
سلام
کمی داریم از بحث اصلی دور میشویم ولی چاره ا نیست ...
پست قبلی به "چرایی" صفحه بندی گذشت.
در این پست کمی در خصوص "چگونگی" آن صحبت میکنیم
اصولاً خود ذات صفحه بندی در مبنای کامل و بزرگش یک Cache دیگر کوچک کنارش نیاز دارد.نقل قول:
متاسفانه نتونستم برای صفحه بندی این کار رو انجام بدم و حالت کلی در نظر بگیرم
این کش مخصوص کمک به صفحه بندی است.
برخی از موارد صفحه بندی روی خروجی خالص یک جدول انجام میشود.
ولی در بسیاری موارد دیگر این خروجی یک نوعی SEARCH است.
یا روی ForeginKey ها و Index ها و Text ها و...
مخصوصاً جستجوی های غیر ایندکسی بسیار هزینه بر و سنگین است.
شما نمیتوانید در مقابل حرکت کاربر بین صفحات مختلف هربار یکمرتبه این جستجو های سنگین را به سیستم تحمیل کنید.
برای صفحه بندی باید خروجی های SEARCH کش شود.
این کش میتواند فقط شامل PrimaryKey سطرهای یافته شده باشد. (سرعت دسترسی بالا و حافظه کم)
در تحت وب و ASP.Net این کش میتواند دو جدول در دیتابیس باشد.
در پروزه های exe میتوان بجای دیتابیس از یک List-int یا List-long و... هم استفاده کرد.
یعنی باید جستجو را یکمرتبه انجام دهید و تک ستون های PrimaryKey این نتایج به داخل کش واکشی شوند.
سپس بخش نمایش از این کش PrimaryKey برای صفحه بندی استفاده کند.
اگر این کش با جداول خود دیتابیس باشد، هم میتوان عدد RowNumber را به خود جدول اضافه کرد و هم میتوان از دستور SQL آن استفاده کرد.
اگر هم کش یک List/Array دات نتی باشد (برنامه Exe) که هم Count دارد و هم دسترسی تصادفی دارد و گمانم استفاده از آن نیاز به تشریح هم ندارد.
این موارد را به راحتی میتوان در قالب کدهای مشترک تجمیع کرد.
بدلیل مشکلات زمانی ، نمیتوانم قولی دهم، ولی تلاش میکنیم اگر فرصتی شد روی ارائه یک نمونه کد بسیار ساده صفحه بندی به روش بالا زمان بگذارم...
سلام
متاسفانه به علت مشغله کاری کمی زمان بر شد ولی به بحث اصلی ادامه میدهیم...
رویداد گرایی
هر کلاسی از هر وراثت ، واسط ، شرایط و... میتواند رویداد داشته باشد و اتفاقات و وقایع خود را منتشر کند.
(((
پیاده سازی زیر بنایی یک رویداد در واقع یک مجموعه اشاره گر توابع است.
کدی که قصد گوش دادن به رویداد و مطلع شدن از آن اتفاق را دارد اشاره گر یک تابع نماینده را به فهرست رویداد اضافه میکند.
کلاس اصلی هر وقت تشخیص داد با به جریان انداختن رویداد تمام توابع نماینده را اجرا میکند
)))
هر رویداد یک "امضا تابعی" خاص خود دارد.
(امضا تابع: نوع و ترتیب پارامترهای ورودی یک تابع)
==============
مثال عملی برای درک بهتر کاربرد وسیع این امکان:
به عنوان نمونه حتماً در WinForm از رویداد Click دکمه ها با امضای object, EventArgs استفاده کرده اید.
این رویداد را کلاس Button هرگاه تشخیص دهد کلیک شده به جریان می اندازد و باعث میشود، تمام توابع نماینده گوش دهنده اجرا شوند. گرچه احتمالاً شما معمولاً برای هر رویداد فقط یک تابع نماینده داشته اید ولی در واقع محودیتی وجود ندارد.
در بحث لایه بندی هم لاس ها از لایه های مختلف میتوانند به رویدادهای یک دیگر گوش دهند...
>>> یک مثال عملی جالب تر در انتهای بحث با یک شبه کد بیان شده است.
==============
پیاده سازی:
اولین مطلب قبل بحث میتواند تایین امضای یک رویداد باشد که با کمک Delegate ها انجام میشود.
(((
Delegate ها اشاره گرهای توابع در دات نت هستند و پرداختن به انها خود بحثی مجزا و گفتاری بسیار می طلبد، دوستان برای اطلاعات بیشتر میتوانند به کتاب های موجود و یا MSDN مراجعه کنند.
)))
دات نت یکسری Delegate آماده دارد مثل System.EventHandler و در دات نت سه System.Action و System.Func که بسیار کاربردی هستند و... و...
بعنوان نمونه EventHandler همان delegate آشنای امضای object, EventArgs است که در WinForm به کرات به ان گوش میدهیم!
تعریف یک رویداد با امضای object, EventArgs :
از لحاظ استفاده کاربردی میتوان گفت هر سه شکل تعریف فوق برابر هستند و خیلی تفاوتی برای نحوه استفاده ندارندکد:public event EventHandler NewEventName;
یا
public event Action<object, EventArgs> NewEventName;
یا
public delegate void NewDelegateName(object a, EventArgs b);
public event NewDelegateName NewEventName;
در واقع مهم "امضای تابع" است که در هر سه مورد فوق بطور مستقیم و غیر مستقیم، امضا را روی دو آرگومان object, EventArgs گذاشته ایم، نتیجتاً عملاً سه شکل فوق یک عمل یکسان انجام میدهند.
به جریان انداختن رویداد (در کلاس مالک رویداد):
گوش دادن به یک رویداد در کدی که از کلاس ما استفاده میکند:کد:object s = ...;
EventArgs e = ...;
var handler = this.NewEventName;
if (handler != null) handler(s, e);
یا حتی سینتکس زیر برای کدهای کوچک ترکد:Class1 x;
//...
x = new Class1();
//...
x.NewEventName += NewListenerFunc;
//...
private void NewListenerFunc(object s, EventArgs e)
{
//Any code...
}
بخش AnyCode همان جایی است که کدی خواهید نوشت که در قبال رخ دادن رویداد باید اجرا شود.کد:Class1 x;
//...
x = new Class1();
//...
x.NewEventName += (s, e) =>
{
//Any code...
};
قطع ارتباط و عدم گوش دادن به رویداد:
=====کد:x.NewEventName -= NewListenerFunc;
مثال ما در این پست برای کلاس ناهمزمان با پشتیبانی رویداد پیشرفت کار:
میتوان کلاسی برای کپی فایل ها، فشرده سازی، بروزرسانی نرم افزار، انتقال اطلاعات دیتابیس، پشتیبان گیری اطلاعات و... در لایه های پایین نوشت بطوریکه مستقل از لایه UI و تکنولوژی آن (WinForm,Wpf, Web, Service و...) باشد. ولی با این وجود این کدها بطور طبیعی نیاز دارند تا حین کارکرد مواردی را به لایه UI یا کاربر گزارش دهند از جمله درصد پیشرفت کار، عملیات جاری در حال انجام و... و تصمیم نمایش و عدم نمایش و طریقه نمایش را بر عهده لایه UI بگذارند.
کد کلاس اصلی در لایه پایین
کد لایه UI که در واقع مستقل از مکانیزم لایه پایین است و به راحتی میتوان آن را مطابق الگوی Wpf یا ASP.Net و... کرد یا در WinService باشد که اصلاً گزارش دادن این اطلاعات به کاربر برایش مهم نباشد و به رویداد مربوطه گوش ندهد و...کد:public delegate void PercentReportDelegate(int percent, string operationtitle);
public class AsyncOperation
{
public event PercentReportDelegate PercentReport;
public void Start()
{
//...
System.Threading.ThreadPool.QueueUserWorkItem(this.AsyncStart);
//...
}
private void AsyncStart(object state)
{
//...
int percent = 0;
string title = null;
//...
while (...)
{
//...
percent = ...;
title = "phase ...";
//...
this.OnPercentReport(percent, title);
//...
}
//...
}
protected virtual void OnPercentReport(int percent, string operationtitle)
{
var handler = this.PercentReport;
if (handler != null) handler(percent, operationtitle);
}
}
==============کد://WinForm UI Layer
public partial class Form1
: System.Windows.Forms.Form
{
private AsyncOperation m_Engine;
public Form1()
{
this.InitializeComponent();
this.m_Engine = new AsyncOperation();
this.m_Engine.PercentReport += this.PercentReportListener;
}
private void btnStart_Click(object sender, EventArgs e)
{
//...
this.m_Engine.Start();
//...
}
private void PercentReportListener(int percent, string operationtitle)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new PercentReportDelegate(this.PercentReportListener), percent, operationtitle);
return;
}
this.progressBar1.Value = percent;
this.label1.Text = operationtitle;
}
}
مطلب اول:
لازم میدانم که حتماً بیان کنم شیوه دیگری از رویداد گرایی وجود دارد که بیش از رویداد گرایی با نام Callback شناخته میشود که در اصل بسیار مشابه رویدادگرایی بیان شده فوق است و طی آن میتوانید تابع نماینده ای برای ارتباط با کد خودتان به لایه پایین تحویل دهید تا با آن بتواند کد لایه بالاتر را (معمولاً در حین انجام کار یا پایان کار) اجرا نماید.
مطلب دوم:
تمام موارد فوق عین در VB.Net هم قابل پیاده سازی و انجام است، طبیعتاً سینتکس نوشتاری خودش را دارد.
حقیقتش دیگر حوصله کافی نوشتن کدهای VB.Net اش را هم نداشتم ولی اگر دوستان با هر بخشی از ان در VB.Net مشکلی داشتند در تالار مطرح بفرمایند، سایر دوستان عزیز و همچنین خودم انشاا... پاسخ خواهیم داد.
مطلب آخر:
در آخر لازم میدانم متذکر شوم که مطالب فوق فقط سرنخ های این کار بوده و شاید 33% مطالب بیان شده و جزئیات و قابلیت های متنوع دیگری در این حیطه وجود دارد که دوستان برای تکمیل بحث و قابلیت های این حیطه میتوانند به کتوب و MSDN مراجعه کنند.
==============
موفق باشید.