الگوی Information Expert

بسیاری از مشکلات ما با تمرکز برروی مسائل پایه حل خواهند شد.

امروز با استاد گرانقدرم آقای شهبازیان جلسه بسیار عالی داشتم و ایشون کتاب :

Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development (3rd Edition) [Hardcover]

به من معرفی کردند که بسیار کتاب با ارزشی بود.این کتاب درباره تعدادی از اصول صحبت کرده که از مفاهیم پایه وبنیادین Object Oriented است.یکی از این مسائل GRASP که شامل ۹ الگو است را در زیر مشاهده می کنید:

Controller
Creator
High Cohesion
Indirection
Information Expert
Low Coupling
Polymorphism
Protected Variations
Pure Fabrication

در این پست قصد دارم شما را با  Information Expert آشنا کنم.

این الگو مشکل اصول واگذاری مسئولیت به اشیا را حل می کند.یعنی مسئولیت را به کلاسی می دهد که اطلاعات کافی برای انجام کارهای مورد نیازش را دارد.

با یک مثال بهتر توضیح خواهم داد:

از شما خواسته می شود که یک پمپ بنزین را شبیه سازی کنید.

در پمپ بنزین چه عملیات انجام می شود؟

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

بیایید نیازهایمان را بررسی کنیم :

  1. مدیریت ورود خروج هر ماشین
  2. محاسبه قیمت فروش کل روز
  3. ظرفیت باک هر ماشین
  4. اطلاع از اینکه چه نوع بنزینی قرار است باک با آن پر شود.
  5. زمان لازم برای سوخت گیری هر ماشین
  6. اطلاع از وضعیت هر جایگاه

خب تا به اینجا نیازمندی هایمان را بررسی کردیم حالا باید موجودیت هایمان را مشخص کنیم.

تا به اینجا ما یک پمپ بنزین خواهیم داشت که تعدادی جایگاه دارد هر جایگاه هم یک ماشین را در خود جای داده است علاوه بر آن پمپ بنزین نیز دارای یک صف هم است.

Grasp

واگذاری مسئولیت:

  1. مدیریت ورود خروج هر ماشین:چه موجودیتی بهتر از پمپ بنزین می داند وضعیت جایگاه هایش چیست؟
    پس وظیفه کنترل ورود خروج به عهده موجودیت  پمپ بنزین  خواهد بود.
  2. محاسبه میزان فروش:هر پمپ بنزین تعدادی جایگاه دارد که درون هر جایگاه  مقدار لیتر فروخته شده بنزین و نوع آن وجود دارد.بنابراین این مسئولیت نیز به پمپ بنزین سپرده می شود.
  3. هر ماشین چقدر بنزین نیاز دارد:این مسئولیت را موجودیت ماشین انجام می دهد.
  4. چه نوع بنزینی قرار است زده شود:این مسئولیت  هم باید به ماشین واگذار شود.
  5. زمان لازم برای سوخت گیری چقدر است:هر ماشین مقدار لیتر مورد نیاز سوخت خود را می داند.ولی سرعت سوخت گیری در هر جایگاه فرق می کند بنابراین مسئولیت این کار با جایگاه است.
  6. اطلاع از وضعیت هر جایگاه :وظیفه جایگاه است که به پمپ بنزین اعلام کند که در حال حاضر خالی است و منتظر ماشین است.

در آخر باید بگویم که ممکن است در این مثال عقیده شما از واگذاری مسئولیت ممکن است کمی متفاوت باشد ولی نکته کلیدی در این الگو واگذاری مسئولیت به کلاسی است که اطلاعات لازم برای انجام کاری را دارد.

یا بهتر بگویم که کلاس های POCO بین لایه های مختلف انتقال داده می شوند ولی در Business این شی Businessی است که خواص یک شی را دارد و مسئولیت ها را هم همین شی دارد.

به عنوان مثال:شی person را در نظر بگیرید که می خواهد به وسیله نام و نام خانوادگیش خود را معرفی کند.جال اگر شما باشید مسئولیت معرفی را به خود کلاس می دهید یا به یک کلاس دیگر؟

Strong-Named Assemblies #2

نصب ساده برنامه (Privately Deployed Assemblies) را در پست های قبلی توضیح دادم. در واقع کپی کردن اسمبلی های برنامه در همان دایرکتوری که برنامه در آن قرار دارد Privately Deploy می گویند.

حال فزض کنید که نیاز است که از یک اسمبلی در برنامه های مختلف استفاده شود در این حالت نیاز است که اسمبلی در یک محل شناخته شده برای CLR نصب شود تا در صورت نیاز CLR آن محل را برای پیدا کردن اسمبلی مورد نظر جستجو کند.

حال فرض کنید که دو کمپانی یک اسمبلی با نام something.dll را عرضه می کنند.در این حالت CLR چگونه باید بین این دو اسمبلی تمایز قائل شود؟

پس راهکاری نیاز است که منحصر به فرد بودن اسمبلی را تضمین کند.

مایکروسافت راهکاری که برای این کار ارائه داده Strong-Named Assemblies است.که این راهکار از مفاهیم cryptographic و hash استفاده  می کند.

Strongly-Named Assembly یک Assembly است که توسط  کلید خصوصی و عمومی انتشار دهنده اسمبلی امضا می شود.

امضا شدن اسمبلی باعث یکتا شدن اسمبلی در کل دنیا می شود و می توان آن را در هر جایی از سیستم کپی کرد.

۴ خصوصیت است که اسمبلی  Strongly-Named را مشخص میکند:

 

  1. Fullname
  2. Version Number
  3. Culture
  4. Public key(در قسمت بعدی توضیح خواهم داد)

پس در زمانی که یکتایی یک اسمبلی تضمین شود در این حالت است که ما مطمئن می شویم که اگر از یک اسمبلی استفاده می کنیم مثلا برای مایکروسافت است و نه برای یک هکر چون CLR به وسیله ۴ خصوصیت بالا است که به دنبال اسمبلی برای لود کردن آن خواهد گشت.

Strong-Named Assemblies #1

در دو بخش قبل با مفاهیم CLR,Assembly و Module آشنا شدید با نحوه  packaging و deployment توانسیتم که یک اسمبلی رو دیپلوی کنیم.

در این سری از مطالب قصد دارم شما را با Strongly named assembly و shared assemblyها آشنا کنم.

در یکی از پست های پیشین گفته شد که مایکروسافت در عدم پایداری امتیازات بالایی به خودش اختصاص داده،شاید یک دلیلش ورژنینگ سخت باشه.چرا که شما نمی تونید این اطمینان رو بدید که اگر یک بیت از کدرو تغییر بدید و اون رو در کامپیوتر کاربر نصب کنید در این حالت برنامه به درستی و مثل قبل از تغییر کار خواهد کرد.

Versioning

توسعه دهندگان کد های خودشون رو بسته بندی می کنند و کدها توسط کاربران مختلف استفاده می شن حالا فرض کنید که این کدها دارای باگ هایی نیز هست و از طرفی دیگر افزودن ویژگی های جدید نیز باعث لزوم بروزرسانی اسمبلی های توزیع شده در سمت کاربر میشه.

VersionCartoon

بنابران نیاز همیشگی به بروزرسانی اسمبلی ها باعث بوجود آمدن مشکلات زیادی خواهد شد که در صورتی که به درستی مدیریت نشود باعث خسارت های فراوان می شود.

دات نتی ها بدانند!

چرا با وجود اینکه من مثلا ۵ گیگ رم خالی دارم باز هم به OutOfMemoryException بر می خورم:

شما برنامه را در چه نسخه از ویندوز اجرا کرده اید؟۳۲ بیتی؟خب معلومه چونکه در ویندوز ۳۲ بیتی نمی توان ۲ گیگ رم را آدرس دهی کرد.

آیا باید finalizer / destructor نوشت؟

در ۹۹ درصد موراد نه.۱ درصد باقی هم شاید نه.

چرا ۰٫۱ + ۰٫۲ جوابش ۰٫۳ نمی شود؟

دلایلش زباده ولی راه حلش استفاده از تایپ decimal است.

آیا نیاز هست من این فیلد را  volatile در نظر بگیرم؟

اگر شما در حال انجام این کار هستید کارخطرناکی را می خواهید انجام دهید.بسیاری از کارشناسان استفاده shared-memory در برنامه های multithreading توصیه نمی کنند.

فرق thread با Async چیست؟

لطفا برید تعریف async رو از اینجا بخونید.

Assembly Probing در دات نت

کاربر و ادمین سیستم می توانند بر برخی از جنبه های اجرایی یک برنامه تاثیر بگذارند.به طور مثال می توانند جای یک اسمبلی را عوض کرده و آن را در یک دایرکتوری دیگر قرار دهند.

برای این منظور یک فایل پیکربندی در دایرکتوری برنامه وجود دارد که  ساختار آن XML است.که می توان یک سری از تنظیمات را در داخل آن انجام داد.مثلا شما می توانید جای اسمبلی های برنامه را تغییر دهید در این حالت شما باید در این فایل مسیر جدید این اسمبلی ها را مشخص کنید در غیر این صورت با خطای System.IO.FileNotFoundException روبرو خواهید شد.

با یک مثال عملی تر این موضوع را توضبیح خواهم داد:

ساختار زیر را برای برنامه در نظر بگیرید:

 دایرکتوری برنامه AppDir directory
فایل اصلی برنامه Program.exe
فایل پیکربندی Program.exe.config

در این حالت کاربر در صورتی بخواهد اسمبلی های برنامه را به زیر شاخه برنامه اصلی در فولدری به اسم AuxFiles منتقل کند :

 دایرکتوری حاوی اسمبلی و ماژول ها AuxFiles subdirectory
اسمبلی  MultiFileLibrary.dll
ماژول FUT.netmodule
ماژول RUT.netmodule

در این حالت چون CLR موفق به پیدا کرد اسمبلی ها در دایرکتوری برنامه نمی شود برای جلوگیری از خطا نیازمند به تنظیم کانفیگ زیر خواهد بود:

 

<configuration>
<runtime>
<assemblyBinding xmlns=”urn:schemas­microsoft­com:asm.v1″>
<probing privatePath=”AuxFiles” />
</assemblyBinding>
</runtime>
</configuration>

در این حالت اگر CLR بتواند در دایرکتوری اصلی اسمبلی ها را پیدا کند به فولدر AuxFiles کاری ندارد در غیر آن صورت در داخل AuxFiles به دنبال اسمبلی خواهد گشت.

privatePath را می توان به وسیله کاما(,) مقدار دهی کرد.توجه کنید که مسیر قابل قبول مسیر نسبی است.

CLR زمانی که نیاز دارد تا اسمبلی را بارگذاری کند چندین مسیر را جستجو می کند.فزض کنید که firstPrivatePathand و secondPrivatePath در فایل پیکربندی نیز ذکر شده باشد در این حالت زبر شاخه های زیر را جستجو خواهد کرد:

 زیر شاخه اصلی AppDir\AsmName.dll
زیر شاخه همراه با نام اسمبلی AppDir\AsmName\AsmName.dll
فولدری که در کانفیگ ذکر شده AppDir\firstPrivatePath\AsmName.dll
زیر شاخه فولدری که در کانفیگ ذکر شده که همنام اسمبلی است AppDir\firstPrivatePath\AsmName\AsmName.dll
فولدر دومی که در کانفیگ ذکر شده AppDir\secondPrivatePath\AsmName.dll
زیر شاخه فولدردومی که در کانفیگ ذکر شده که همنام اسمبلی است AppDir\secondPrivatePath\AsmName\AsmName.dll

اگر باز هم نتوانست اسمبلی را پیدا کند به جای .dll به دنبال .exe خواهد گشت.در غیر این صورت خطای FileNotFoundException را خواهد داد.

برای satellite assembly ها نیز مسیر ها را با توجه به کالچر جستجو می کند در مثال زیر CLR در مسیر های زبر به دنبال اسمبلی با کالچر en-USخواهد گشت.

C:\AppDir\en­US\AsmName.dll
C:\AppDir\en­US\AsmName\AsmName.dll
C:\AppDir\firstPrivatePath\en­US\AsmName.dll
C:\AppDir\firstPrivatePath\en­US\AsmName\AsmName.dll
C:\AppDir\secondPrivatePath\en­US\AsmName.dll
C:\AppDir\secondPrivatePath\en­US\AsmName\AsmName.dll

C:\AppDir\en­US\AsmName.exe
C:\AppDir\en­US\AsmName\AsmName.exe
C:\AppDir\firstPrivatePath\en­US\AsmName.exe
C:\AppDir\firstPrivatePath\en­US\AsmName\AsmName.exe
C:\AppDir\secondPrivatePath\en­US\AsmName.exe
C:\AppDir\secondPrivatePath\en­US\AsmName\AsmName.exe

C:\AppDir\en\AsmName.dll
C:\AppDir\en\AsmName\AsmName.dll
C:\AppDir\firstPrivatePath\en\AsmName.dll
C:\AppDir\firstPrivatePath\en\AsmName\AsmName.dll
C:\AppDir\secondPrivatePath\en\AsmName.dll
C:\AppDir\secondPrivatePath\en\AsmName\AsmName.dll
C:\AppDir\en\AsmName.exe

C:\AppDir\en\AsmName\AsmName.exe
C:\AppDir\firstPrivatePath\en\AsmName.exe
C:\AppDir\firstPrivatePath\en\AsmName\AsmName.exe
C:\AppDir\secondPrivatePath\en\AsmName.exe
C:\AppDir\secondPrivatePath\en\AsmName\AsmName.exe

چون حالت های جستجو برای CLR زمانگیر است بهتر است که در این حالت در فایل کانفیگ برای محدود کردن جستجو یک یا جند کالچر مشخص شود.

برای راهنمایی بیشتر به این لینک مراجعه شود.

نکته:

نام فایل پیکربندی و مسیر آن مهم است برای برنامه اجرایی باید نام فایل اجرایی به همراه .config باشد و در مسیر اصلی برنامه باشد.در برنامه asp.net باید به اسم web.config باشد.

نصب ساده برنامه (Privately Deployed Assemblies)

در مطلبی که درباره اهداف دات نت برای Deployment نوشتم به مشکلات نصب در قبل از زمان دات نت اشاره کردم یکی از آن ها فرایند نصب پیجیده بود:

زمانی که یک برنامه را نصب می کنید تاثیر یسیار زیادی در جای جای سیستم دارد از بروزرسانی رجیستری تا کپی شدن فایل ها در قسمت های مختلف.مشکل اینجاست که به صورت ایزوله برنامه ما نصب نمی شود و ما به راحتی امکان بک آپ گیری از برنامه را با کپی کردن فولدر برنامه نخواهیم داشت و برای انتقال به سیستم دیگر نیاز به نصب مجدد خواهیم داشت. به خاطر همین است که بعد از پاک کردن برنامه باز هم یک حسی نسبت به عدم پاکسازی کامل سیستنم از برنامه خواهیم داشت.

حال حالتی را در نظر بگیرید شما فقط با کپی پیست کردن اسمبلی ها و بدون هیچ فرایند پیجیده ای می توانید برنامه خود را نصب کنید.در این حالت هیچ تغییری در سیستم وجود ندارد و به راحتی می توان از برنامه فایل پشتیبان تهیه کرد یا آن را با delete کردن uninstall کرد.به این حالت از نصب Privately Deployed Assemblies گفته می شود.زیرا فابل های اسمبلی با باقی برنامه به اشتراک گذاشته نمی شوند.

البته ابزارهای بسیار زیادی برای ایجاد فایل نصب برنامه وچود دارند که کارهای زیادی را برای ما انجام میدهند.به عنوان مثال ایجاد shortcut روی desktop کاربر و یا نصب پیشنیاز ها یک از این ابزار خود ویژوال استدیو است.

شما می توانید به وسیله ویژوال استدیو  که دارای یک مکانیزم برای نصب برنامه است استفاده کنید:روی پروژه راست کلیک کنید و properties را انتخاب کنید سپس به تب Publish بروید:

Publish

لینک های تکمیلی:

Create MSI or setup Project with visual studio 2012

Publish Page, Project Designer

نگاهی به Culture در دات نت

همانطور که در قسمت های قبلی گفته شد عدد ورژن در اسمبلی یکی از اطلاعاتی است که اسمبلی را متمایز می کند.علاوه بر آن Culture نیز در اسمبلی همین کار را انجام میدهد و قسمتی از شناسه اسمبلی است.کار کالچر تعیین  فرمت date, number, and currency , … است.

برای هر Cultureی یک کد استاندارد وجود دارد که نمونه ای از آن را در زیر مشاهده می کند:

Language Culture Name Display Name Culture Code ISO 639x Value
af-ZA Afrikaans – South Africa ۰x0436 AFK
sq-AL Albanian – Albania ۰x041C SQI

فرض کنید شما در حال ساخت یک اسمبلی هستید که در آن نیازی به مشخص کردن Culture نیست.در این حالت شما برای اسمبلی کالچری را مشخص نمی کنید وبه این نوع اسمبلی Neutral Culture گفته می شود.

زمانی که شما در حال ساخت یک اسمبلی هستید که دارای چندین Culture  است در این حالت شما می توانید یک اسمبلی با Culture پیش فرض ایجاد کنید و به ازای هر Culture یک اسمبلی بدون کد که به آن Stellite assembly  گفته می شود ایجاد کنید.به این نکته توجه کنید که در هنگام دیپلوی اسمبلیCulture  را می بایست در مسیر برنامه در فولدری به اسم Culture قرار دهید در این حالت از در Runtime از طریق System.Resource.ResourceManager به آن دسترسی خواهید داشت.

culture

نکات تکمیلی:

versioning اسمبلی به شیوه مایکروسافت

جدول زیر را درنظر بگیرید:

Revision Number Build Number Minor Number Major Number
۳ ۷۹۱ ۵ ۲

Major Number و Minor Number:دو ورژنی است که به صورت عمومی انتشار داده می شود.

Build Number:اگر شما روزی یک بار عملیات Build را انجام می دهید در این صورت این عدد یکی باید اضافه شود.

Revision Number :عدد بازبینی است و اگر در یک روز دوبار Build را انجام دادید و یک باگ را فیکس کردید این عدد باید یکی اضافه شود.

CLR به صورت اتوماتیک آخرین ورژن اسمبلی درخواستی را که Major Number و Minor Number یکسان باشد را پیدا می کند.ممکن است بین انواع ورژن هایی که در پست پیش گفته شده گیج کننده باشد که در پایین توضیح داده شده:

  • AssemblyFileVersion:این ورژن به وسیله CLR نادیده گرفته می شود و هیچ دخل و تصرفی در لود شدن اسمبلی ندارد و فقط برای اطلاع درباره اسمبلی است.در ضمن وظیفه بروزرسانی این به عهده خودمان است.این ورژن در win32 version resource ذخیره می شود.
  • AssemblyInformationalVersion:این ورژن به وسیله CLR نادیده گرفته می شود و مربوط به ورژن محصولی است که اسمبلی در آن استفاده شده برای مثال ورژن ۲٫۵ یک محصول شاید حاوی اسمبلی ورژن ۱ باشد.این ورژن در win32 version resource ذخیره می شود.
  • AssemblyVersion :این ورژن برای CLR مهم است در واقع به وسیله این ورژن است که CLR می تواند اسمبلی را لود کند.این ورژن در Assembly Def ذخیره میشود.به وسیله این ورژن است که یکتایی اسمبلی تضمین می شود.ما تازمانی که اسمبلی آماده دیپلوی نشده نباید ورژن آن را بالا ببریم.

Assembly Version Resource

زمانی که شما یک اسمبلی می سازید در این حالت خروچی شما یک فایل PE حاوی Win32 Version Resource که به وسیله مشاهده properties فایل و همجنین صدا زدن GetVesrionInfo از System.Diagnostics.FileVersionInfo می توان آن را یافت.

Version

اگر در ویژوال استدیو کد می زنید پروژه شما حاوی یک فولدر به نام Properties است که وسیله Attribute هایی که در زیر توضیح داده شده ورژن های مختلف یک اسمبلی را می توان مشخص کرد.

using System.Reflection;
// FileDescription version information:
[assembly: AssemblyTitle("MultiFileLibrary.dll")]
// Comments version information:
[assembly: AssemblyDescription("This assembly contains MultiFileLibrary's types")]
// CompanyName version information:
[assembly: AssemblyCompany("Wintellect")]
// ProductName version information:
[assembly: AssemblyProduct("Wintellect (R) MultiFileLibrary's Type Library")]
// LegalCopyright version information:
[assembly: AssemblyCopyright("Copyright (c) Wintellect 2013")]
// LegalTrademarks version information:
[assembly:AssemblyTrademark("MultiFileLibrary is a registered trademark of Wintellect")]
// AssemblyVersion version information:
[assembly: AssemblyVersion("3.0.0.0")]
// FILEVERSION/FileVersion version information:
[assembly: AssemblyFileVersion("1.0.0.0")]
// PRODUCTVERSION/ProductVersion version information:
[assembly: AssemblyInformationalVersion("2.0.0.0")]
// Set the Language field (discussed later in the "Culture" section)
[assembly:AssemblyCulture("")]

به وسیله AssemblyVersion است که اسمبلی را لود می کند ولی جالب است که بدانید که ویندوز در properties آن را نشان نمی دهد.

برای تعیین ورژن در ویژوال استدیو علاوه بر Attribute ها می توانید به شکل زیر عمل کنید:

assembly version

Assembly Linker در دات نت چیست؟

حالتی را در نظر بگیرید که نیاز مند آن هستید چند ماژول را تبدیل به اسمبلی کنید در این حالت اگر  کامپایلری که با آن می خواهید این کار را انچام دهید قابلیت پشتیبانی از سوئیچ addmodule را نداشته باشد در این حالت شما بایستی به وسیله Al.exe این کار را انجام دهید.به وسیله  Al.exe شما می توانید یک فایل exe یا dll تولید کنید که فقط دارای مانیفست برای مشخص کردن تایپ های باقی ماژول هایی است که شما از آن ها یک اسمبلی ساخته اید.

عکس زبر نشان دهنده موضوع خواهد بود.

Assembly Linkerشکل بالا مشخص کننده ترکیب دو ماژول در یک اسمبلی است که با دستور

al /out: MultiFileLibrary.dll /t:library FUT.netmodule RUT.netmodule

تولید شده اند.باز تاکید می کنم که شما در زمان استفاده از al نمی توانید چند اسمبلی را درون یک فایل نگهداری کنید و کار al  فقط ساخت یک اسمبلی که حاوی متادیتا برای ارجا به ماژول ها است.

نکته آخراینکه al می تواند خروجی ویندوز،کنسول و یا dll داشته باشد.