نظرات اشتراک‌ها
آیا الگوی Service Locator یک Anti-Pattern است؟
ضد الگو.
مثلا یکی از الگوهای برنامه نویسی شیء گرا این است که کلاس‌های کوچک و تک مسئولیتی داشته باشید تا نگهداری آن در طول زمان ساده‌تر شود. نقطه مقابل آن یک ضد الگو است به نام God object یا کلاسی که همه چیزی داخل آن پیدا می‌شود و اطلاعات زیادی دارد.
اشتراک‌ها
باز نویسی ساختمان داده ها و الگوریتم های معروف با ES6

اگر تا الان تصمیم نگرفته اید که ES6 را یاد بگیرد این مخزن به شما کمک خواهد کرد که ساختمان داده و الگوریتم‌های معروف با ES6 باز نویسی کنید!

 منبع :https://telegram.me/webly 
باز نویسی ساختمان داده ها و الگوریتم های معروف با ES6
مطالب
برنامه نویسی پیشرفته JavaScript - قسمت 5 - معرفی برخی عملگرها

معرفی برخی عملگرها

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


عملگر typeof

از آنجائیکه جاوا اسکریپت دارای نوع داده‌ای ضعیف یا Loosely Typed می‌باشد، باید در بکارگیری متغیرها و یا آرگومانهای ورودی توابع، دقت لازم را داشته باشیم تا خطایی در اجرای کد یا محاسبات به وجود نیاید. بنابراین به راهکارهایی نیاز داریم تا بتوانیم نوع داده‌ای یک متغیر را تشخیص دهیم و قبل از بکارگیری آنها صحت و اعتبار داده‌های ورودی را بررسی کنیم. با استفاده از عملگر typeof می‌توانیم نوع داده‌ای یک متغیر را تشخیص دهیم که برای هر نوع داده‌ای مقادیر زیر را بر میگرداند:

· برای متغیرهایی که شامل مقدار undefined می‌باشند مقدار "undefined"

· برای متغیرهای منطقی یا Boolean مقدار "boolean"

· برای متغیرهای رشته‌ای یا String مقدار "string"

· برای متغیرهای عددی و مقادیر NaN و Infinity مقدار "number"

· برای تابع مقدار "function"

· برای اشیا و مقادیر null مقدار "object"

var x;
var n = 12;
var obj = {};
var fn = function () { };
var a = new Array();

alert(typeof x);        // "undefined"
alert(typeof n);        // "number"
alert(typeof obj);     // "object"
alert(typeof fn);       // "function"
alert(typeof a);        // "object"

عملگر instanceof

عملگر typeof بهترین روش جهت تشخیص نوع داده‌ای متغیرهایی است که دارای نوع داده‌ای پایه یا Primitive Type هستند. اما جهت تشخیص نوع داده‌ای اشیاء و به صورت کلی انواع ارجاعی، این عملگر فقط مقدار "object" را برمیگرداند و اشاره‌ای به ماهیت واقعی آن Object ندارد. برای این منظور می‌توانیم از عملگر instanceof استفاده نماییم تا بررسی کنیم یک نوع ارجاعی از جنس چه نوع Object ی می‌باشد. شکل کلی استفاده از این عملگر به صورت زیر است:

result = variable instanceof constructor

اگر variable ، از جنس نوع ارجاعی تعیین شده در بخش سازنده یا constructor باشد، عملگر instanceof مقدار true را بر می‌گرداند. به مثال زیر توجه کنید:

var a = new Array();
alert(a instanceof Array); // true
alert(a instanceof Object);   // true
alert(a instanceof Date); // false
توجه داشته باشید که اگر عملگر instanceof برای یک نوع ارجاعی به کار رود و با سازنده Object بررسی شود، همیشه مقدار true برمی گرداند.

عملگر in

همانطور که قبلا اشاره شد، جهت دسترسی به اعضای یک شیء، می‌توان با آن شیء همانند یک آرایه رفتار نمود. به عبارتی دیگر میتوان نام یک ویژگی یا تابع را در [] قرار داد تا به مقدار آن دسترسی داشت. بنابراین می‌توان همانند یک آرایه و با استفاده از یک حلقه‌ی for-in تمامی اعضای یک شیء را پیمایش نمود. در واقع عملگر in در این حلقه بررسی می‌کند چه ویژگی‌ها و توابعی در یک شیء وجود دارند و تمامی آنها را بر می‌گرداند. به مثال زیر توجه کنید:

var person = {
    name: "Meysam",
    age: 33,
    sayInfo: function () {
        alert(name + ":" + age);
    }
};

for (var i in person) 
    alert(i + " => " + person[i]);

خروجی :

     name => Meysam

    age => 33

    sayInfo => function() {
        alert(name + ":" + age);
    }
در مثال فوق، توسط حلقه‌ی for-in ، شیء person را پیمایش نمودیم. در این پیمایش، متغیر i ، به تک تک اعضای موجود در این شیء اشاره می‌کند. بنابراین متغیر i شامل نام ویژگی یا تابع می‌باشد و person[i] مقدار موجود در آن ویژگی یا محتوای تابع را بر میگرداند.

کاربرد دیگر عملگر in بررسی وجود یک ویژگی یا تابع در یک شیء می‌باشد. اگر ویژگی یا تابع مورد نظر در شیء وجود داشته باشد، مقدار true را  بر می‌گرداند. به مثال زیر توجه کنید:

alert("name" in person); // true
alert("sayInfo" in person); // true
alert("birth" in person); // false


عملگر delete

از عملگر delete جهت حذف یک ویژگی و یا یک تابع از یک شیء استفاده می‌شود. به مثال زیر توجه کنید:

var person = {
    name: "Meysam",
    age: 33,
    sayInfo: function () {
        alert(name + ":" + age);
    }
};

alert("sayInfo" in person); // true
delete person.sayInfo;
alert("sayInfo" in person); // false
در مثال فوق پس از به کارگیری عملگر delete ، تابع sayInfo از شیء person حذف شده است. بنابراین در آخرین alert اعلام می‌کند که شیء person دیگر شامل این تابع نمی‌باشد.


ویژگی constructor

پس از عملگرهای فوق، یکی از پرکاربردترین ویژگی‌هایی که برای اشیاء وجود دارد، ویژگی constructor می‌باشد. در واقع این ویژگی نیز یکی از راهکارهای بررسی صحت و اعتبار متغیرها، آرگومانها و اشیا می‌باشد. ویژگی constructor ، به تابع سازنده‌ی یک شیء اشاره می‌کند و آن سازنده را به عنوان خروجی بر میگرداند. دقت داشته باشید که خروجی این ویژگی، خود تابع سازنده می‌باشد و یک مقدار رشته‌ای نیست. به مثال زیر توجه کنید:

var obj = {};
var a = new Array();
var x = 10;

alert(obj.constructor);
alert(obj.constructor === Object);
alert(typeof obj.constructor);
alert(a.constructor);
alert(x.constructor);

خروجی :

    function Object() { [native code] }
    true
    function
    function Array() { [native code] }
    function Number() { [native code] }
همانطور که در مثال فوق مشاهده می‌نمایید، کدهای obj.constructor ، a.constructor و x.constructor تابع سازنده‌ی این اشیا را برگردانده است. در مقایسه obj.constructor===Object نیز مشاهده می‌کنید که خروجی این ویژگی یک شیء می‌باشد و در typeof obj.constructor هم نشان دادیم که نوع این ویژگی یک تابع است.

در اینجا دیگر آماده‌ی ورود به برنامه نویسی شیء گرا در جاوا اسکریپت می‌باشیم که در مقالات بعدی به آن خواهیم پرداخت و همچنین با جزئیات بیشتری اشیاء را تشریح می‌نماییم. 

مطالب
بررسی مفاهیم متغیرهای Value Type و Reference Type در سی شارپ
نوع داده(Data Type) ، متغیر‌ها(Variables) ، انواع مقداری(Value Type) ، انواع ارجاعی(Reference Type)

مقدمه :
نوع داده‌ها، اجزای اصلی سازنده‌ی یک زبان برنامه نویسی و شبیه قواعد هر زبانی هستند.
مفاهیمی که در این مطلب بررسی خواهد شد :
 • Data Type نوع داده
 • Variables  متغیرها
 • Naming Convention قرارداد‌های نامگذاری
 • Value Type/Reference Type انواع مقداری و ارجاعی
 • Stack/heap memory  حافظه پشته و هرم

نوع داده

در دنیای واقعی، برای نگهداری مواد مختلف، ظروف مختلفی با اندازه‌های مختلفی طراحی شده است. در دنیای برنامه نویسی، به تناسب اطلاعاتی که می‌خواهیم در حافظه ذخیره کنیم، باید نوع ظرف ذخیره سازی را انتخاب کنیم. نوع ظرف ذخیره سازی را در دنیای برنامه نویسی، نوع داده‌ها مشخص می‌کنند.
در دات نت، همه‌ی نوع داده‌ها (Data Type) بصورت مستقیم و یا غیر مستقیم، از کلاس System.Object مشتق شده‌اند.


متغیرها

متغیر‌ها برای ذخیره‌ی مقادیر (اطلاعات)، استفاده می‌شوند. به این مثال دقت کنید: ما یک کیف داریم که در آن یک کتاب قرار دارد. در اینجا کیف نقش متغیر و کتاب نقش مقدار (value) را ایفا می‌کند. اندازه‌ی کیف همان نوع داده (Data Type) در دنیای برنامه نویسی می‌باشد.


چک کردن سایز نوع داده (Data Type)

ما نیازی به حفظ کردن اندازه‌ی نوع داده‌ها نداریم. در سی شارپ متدی به نام () sizeof مهیا شده است که با چک کردن نوع داده، اندازه‌ی آن را بر حسب بایت نمایش می‌دهد.
به مثال زیر دقت کنید:
Console.WriteLine(sizeof(int));
Console.WriteLine(sizeof(char));
Console.WriteLine(sizeof(bool));
Console.WriteLine(sizeof(decimal));
Console.WriteLine(sizeof(float));
خروجی کد‌های بالا :
 4
2
1
16
4

نکته : متد sizeof فقط برای نمایش اندازه‌ی نوع داده‌های مقداری (value type) می‌تواند مورد استفاده قرار گیرد.


چک کردن نوع داده

ما می‌توانیم نوع داده‌ها را برای بدست آوردن کلاسی که به آن تعلق دارند، چک کنیم.
مثال :
 int a = 23;
float b = 3.14f;
Console.WriteLine(a.GetType());
Console.WriteLine(b.GetType());
خروجی کد‌های بالا : 
System.Int32
System.Single

چک کردن نوع داده‌ی دو شیء

فرض کنید 2 شیء را با نام‌های obj1 و obj2 داریم که هر دو از نوع long هستند. برای اینکه این مقایسه را انجام دهیم، از متد Object.RefrenceEqual می‌توان استفاده کرد.
مثال :
long obj1 = 356;
long obj2 = 54;
float obj3 = 234;
Console.WriteLine(object.ReferenceEquals(obj1.GetType(), obj2.GetType()));
Console.WriteLine(object.ReferenceEquals(obj1.GetType(), obj3.GetType()));
خروجی کد‌های بالا : 
True
False

تعریف یک متغیر ومقدار دهی به آن
سی شارپ یک زبان strongly typed است (البته با در نظر نگرفتن نوع dynamic آن). به این معنا که کلیه‌ی متغیر‌ها، قبل از استفاده باید تعریف و مقدار دهی شوند و بعد از تعریف متغیر، نمی‌توان نوع آن را تغییر داد. رفتار یک متغیر بر اساس نوع انتخابی ما مشخص می‌شود. بطور مثال با انتخاب نوع int تنها می‌توان اعداد صحیح را ذخیره و نگهداری کرد و برای تغییر رفتار متغیر‌ها باید آنها را تبدیل کنیم.

تعریف یک متغیر
برای استفاده از یک متغیر ابتداباید آن را تعریف کنیم :
//<data type> <variable name>;
Int a;

مقداردهی اولیه یک متغیر

مقدار دهی اولیه‌ی یک متغیر با استفاده از عملگر = و نوشتن مقدار مورد نظر برای ذخیره کردن در متغیر، در سمت راست عملگر اتفاق خواهد افتاد.
//<data type> <variable name>=value;
Int a=23;
Int a;//declare تعریف
a=23;//مقدار دهی اولیه initializing
Int a=23;//تعریف و مقدار دهی در یک خط
Int a,b,c=23;//تعریف چند متغیر و مقدار دهی در یک خط


قرار دا‌دهای نام گذاری متغیر‌ها :

در دنیای برنامه نویسی دو نوع قرار داد نام گذاری بسیار متداول وجود دارند:
 1-  camelCase : در این قرار داد، حرف اول کلمه‌ی اول، بصورت کوچک و حرف اول از کلمه‌ی دوم، بصورت بزرگ نوشته خواهد شد. برای مثال: firstName,lastName
 2- PascalCase : در این قرار داد حروف ابتدایی دو کلمه‌ی مجاور، بصورت بزرگ نوشته خواهند شد: FirstName,LastName

چند نکته :
 • نامگذاری متغیر‌ها را می‌توانید با علامت _ و یا @ شروع کنید.
 • کلمات کلیدی (key word) سی شارپ نمی‌توانند به عنوان نام متغیر مورد استفاده قرار بگیرند (مگر آنکه با @ شروع شوند).
 • در بین نام متغیر نباید فضای خالی وجود داشته باشد. کاراکتر‌های سازنده‌ی متغیر می‌توانند اعداد، حروف و زیر خط باشند.
لیستی از نام گذاری‌های مجاز:
 int abc;
long _abcd;
float @abcd;
bool main_button;
decimal piValue;
string firstName;
string first_name;
bool button55_on;
لیستی از نام گذاری‌های غیر مجاز
long _a.5bc5d;
float @ab cd;
decimal pi@Value;
//استفاده از کلمات کلیدی سی شارپ که کامپایلر آنها را مجاز نمی‌داند
bool class;
string namespace;
string string;
int static;
برای مطالعه‌ی کاملتر کلمات کلیدی سی شارپ می‌توانید اینجا را مطالعه کنید.


در ادامه کمی در مورد نوع داده‌ها بحث خواهیم کرد.
در سی شارپ دو مدل نوع داده وجود دارد:
 • انواع مقداری Value Type
 • انواع ارجاعی یا اشاره‌ای Reference Type

انواع مقداری (Value Type) :
 • انواع مقداری مستقیما حاوی داده‌ها هستند. اگر یک متغیر از نوع مقداری را به یک متغیر دیگر تخصیص دهید، مقدار آنها مستقیما کپی می‌شوند؛ برعکس نوع‌های اشاره‌ای که با نخصیص یک متغیر به یک متغیر دیگر، تنها اشاره‌گر به مقدار شیء کپی خواهد شد و نه خود شیء.
 • کلیه نوع‌های مقداری از کلاس ValueType مشتق شده‌اند.
 • در فضای stack  به آنها حافظه تخصیص داده می‌شود.
 • نمی‌توانند مقدار null  بپذیرند. البته با قابلیت nullabletype امکان تخصیص مقدار null به نوع داده‌های مقداری نیز مهیا شده است.
 • همه نوع‌های داده‌های مقداری، یک سازنده پیش فرض دارند که به صورت ضمنی کار مقدار دهی اولیه برای آنها را انجام می‌دهد. برای مطالعه بیشتر درباره مقادیر پیش فرض به اینجا مراجعه کنید.

انواع مقداری به دو دسته‌ی اصلی تقسیم می‌شود :
 • Structs
 • Enumerations

طبقه بندی Structs به صورت زیر است :
 • Numeric Type
* Integral Type : sbyte,short,ushort,int,uint,long,ulong,char
* Floating-Point Types : float,double
* Decimal : decimal
 •  Bool دو مقدار true و false
 • User Defined Struct


نوع داده نال (تهی) پذیر (nullable Type) و چگونگی تعریف آن

در ابتدای معرفی نوع داده‌های مقداری گفتیم همیشه باید وضعیت متغیر مشخص و مقدار دهی اولیه‌ی آن یا به صورت ضمنی و یا آشکار انجام شود. هیچ یک از نوع داده‌های مقداری نمی‌توانند بصورت null تعریف شوند. برای تبدیل یک نوع داده مقداری به صورتی که قابلیت ذخیره‌ی مقدار null را داشته باشد، بعد از نوشتن نوع داده، علامت سوال ؟ قرار می‌دهیم.
 < data type >? < variable name >= null; //syntax

int? a = null; //assigning null
int? b = 55; //assigning null and a value
var? c = 55 //it will give error

نکته :  var نمی‌تواند بصورت nullable تعریف شود.

برای چک کردن مقدار در انواع تهی پذیر (nullable) دو خصوصیت وجود دارد:
 • HasValue
اگر مقداری در متغیر وجود داشته باشد ارزش true  بازگردانده می‌شود؛ در غیر اینصورت ارزش false
 • Value
مقدار واقعی متغیر را باز می‌گرداند.

مثال :
 int? a = null;
int? b = 22;
Console.WriteLine(a.HasValue);
//------------
Console.WriteLine(b.HasValue);
Console.WriteLine(b.Value);
خروجی کد بالا :
 False
True
22

انواع ارجاعی Reference Type

انواع ارجاعی مستقیما حاوی اطلاعات نیستند و ارجاعی هستند به آدرسی از حافظه که حاوی اطلاعات واقعی است. به بیانی دیگر، اشاره‌گری به آدرسی از حافظه هستند.
 • انواع ارجاعی بصورت غیر مستقیم حاوی داده‌ها هستند.
 • در بخشی از حافظه که به آن heap می‌گوییم، به آنها فضا اختصاص داده می‌شود.
 • می‌توانند بصورت null (بدون مقدار) باشند.

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

 • انواع از پیش تعریف شده
  Object,string,dynamic
 • انواع تعریف شده توسط کاربر
        class,interface,delegate

نکته : آدرس مکانی از حافظه که داده‌ها در آن قرار دارند، در بخش پشته یا Stack ذخیره می‌شود و داد‌ه‌ها در فضای heap ذخیره می‌شوند.
مثال :
 test obj; //allocating reference on stack
obj= new test(55);//allocating object on heap

نکته : دو متغیر از نوع ارجاعی می‌توانند به یک آدرس از حافظه اشاره کنند. در شکل زیر این موضوع نشان داده شده است.

 
در شکل زیر طبقه بندی نوع داده‌ها در سی شارپ نشان داده شده است :


• عملیات کپی در نوع داده مقداری
وقتی از یک متغیر مقداری را به یک متغیر دیگر تخصیص می‌دهیم، یک کپی جدید از آن در فضای stack  ایجاد می‌شود. بدین معنی که محتوای دو متغیر یکسان هستند، ولی در دو بخش مجزای در حافظه‌ی Stack قرار دارند. به همین خاطر تغییر  محتوای یک متغیر، محتوای متغیر دیگر را تغییر نمی‌دهد.
مثال :
 int a = 55;//declare a and initialize
int copya = a;//copya contains the copy of value a
دیاگرام حافظه کد بالا :

 

• عملیات کپی، در نوع داده‌ی ارجاعی
وقتی یک متغیر از نوع ارجاعی را به یک متغیر دیگر تخصیص می‌دهیم، دو اشاره‌گر در فضای Stack ایجاد می‌شود که به یک مقدار واحد در حافظه‌ی heap اشاره می‌کنند. آدرس‌های ذخیره شده‌ی در stack  یکسان هستند.
مثال : در اینجا فرض بر این است کهtest یک کلاس تعریف شده‌ی توسط کاربر می‌باشد.
test obj;
obj=new test(23);
test objCopy;
objCopy = obj;

دیاگرام حافظه‌ی قطعه کد بالا به شکل زیر است :



تخصیص حافظه در بخش Stack  و Heap به متغیر‌ها

سیستم عامل و net CLR. حافظه را به دو بخش stack و heap تقسیم بندی می‌کنند.
زمانی که یک متد را فراخوانی می‌کنیم، در بخش پشته به پارامتر‌های متد فضا تخصیص داده می‌شود و بعد از پایان کار متد، فضای اشغال شده‌ی بوسیله GC یا همان Garbage collection  آزاد می‌شود.
تخصیص حافظه در Stack  بر اساس قانون LIFO انجام و به ترتیب و پشت سر هم، حافظه تخصیص داده می‌شود. دیاگرام تخصیص حافظه به stack:


تخصیص حافظه در Heap بصورت تصادفی است؛ بر عکس پشته (stack) که به ترتیب و متوالی انجام می‌شد. انواع ارجاعی در Stack  ذخیره می‌شوند؛ ولی داده‌ی واقعی در heap قرار می‌گیرد.
حافظه‌های پویا در بخش heap و حافظه‌های استاتیک در بخش stack تخصیص داده می‌شوند.
 
مطالب
EF Code First #9

تنظیمات ارث بری کلاس‌ها در EF Code first


بانک‌های اطلاعاتی مبتنی بر SQL، تنها روابطی از نوع «has a» یا «دارای» را پشتیبانی می‌کنند؛ اما در دنیای شیءگرا روابطی مانند «is a» یا «هست» نیز قابل تعریف هستند. برای توضیحات بیشتر به مدل‌های زیر دقت نمائید:


using System;

namespace EF_Sample05.DomainClasses.Models
{
public abstract class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateOfBirth { get; set; }
}
}

namespace EF_Sample05.DomainClasses.Models
{
public class Coach : Person
{
public string TeamName { set; get; }
}
}

namespace EF_Sample05.DomainClasses.Models
{
public class Player : Person
{
public int Number { get; set; }
public string Description { get; set; }
}
}

در این مدل‌ها که بر اساس ارث بری از کلاس شخص، تهیه شده‌اند؛ بازیکن، یک شخص است. مربی نیز یک شخص است؛ و به این ترتیب خوانده می‌شوند:

Coach "is a" Person
Player "is a" Person

در EF Code first سه روش جهت کار با این نوع کلاس‌ها و کلا ارث بری وجود دارد که در ادامه به آن‌ها خواهیم پرداخت:

الف) Table per Hierarchy یا TPH

همانطور که از نام آن نیز پیدا است، کل سلسله مراتبی را که توسط ارث بری تعریف شده است، تبدیل به یک جدول در بانک اطلاعاتی می‌کند. این حالت، شیوه برخورد پیش فرض EF Code first با ارث بری کلاس‌ها است و نیاز به هیچگونه تنظیم خاصی ندارد.
برای آزمایش این مساله، کلاس Context را به نحو زیر تعریف نمائید و سپس اجازه دهید تا EF بانک اطلاعاتی معادل آن‌را تولید کند:

using System.Data.Entity;
using EF_Sample05.DomainClasses.Models;

namespace EF_Sample05.DataLayer.Context
{
public class Sample05Context : DbContext
{
public DbSet<Person> People { set; get; }
}
}

ساختار جدول تولید شده آن همانند تصویر زیر است:


همانطور که ملاحظه می‌کنید، تمام کلاس‌های مشتق شده از کلاس شخص را تبدیل به یک جدول کرده است؛ به علاوه یک فیلد جدید را هم به نام Discriminator به این جدول اضافه نموده است. برای درک بهتر عملکرد این فیلد، چند رکورد را توسط برنامه به بانک اطلاعاتی اضافه می‌کنیم. حاصل آن به شکل زیر خواهد بود:


از فیلد Discriminator جهت ثبت نام کلاس‌های متناظر با هر رکورد، استفاده شده است. به این ترتیب EF حین کار با اشیاء دقیقا می‌داند که چگونه باید خواص متناظر با کلاس‌های مختلف را مقدار دهی کند.
به علاوه اگر به ساختار جدول تهیه شده دقت کنید، مشخص است که در حالت TPH، نیاز است فیلدهای متناظر با کلاس‌های مشتق شده از کلاس پایه، همگی null پذیر باشند. برای نمونه فیلد Number که از نوع int تعریف شده، در سمت بانک اطلاعاتی نال پذیر تعریف شده است.
و برای کوئری نوشتن در این حالت می‌توان از متد الحاقی OfType جهت فیلتر کردن اطلاعات بر اساس کلاسی خاص، کمک گرفت:

db.People.OfType<Coach>().FirstOrDefault(x => x.LastName == "Coach L1")


سفارشی سازی نحوه نگاشت TPH

همانطور که عنوان شد، TPH‌ نیاز به تنظیمات خاصی ندارد و حالت پیش فرض است؛ اما برای مثال می‌توان بر روی مقادیر و نوع ستون Discriminator تولیدی، کنترل داشت. برای این منظور باید از Fluent API به نحو زیر استفاده کرد:

using System.Data.Entity.ModelConfiguration;
using EF_Sample05.DomainClasses.Models;

namespace EF_Sample05.DataLayer.Mappings
{
public class CoachConfig : EntityTypeConfiguration<Coach>
{
public CoachConfig()
{
// For TPH
this.Map(m => m.Requires(discriminator: "PersonType").HasValue(1));
}
}
}

using System.Data.Entity.ModelConfiguration;
using EF_Sample05.DomainClasses.Models;

namespace EF_Sample05.DataLayer.Mappings
{
public class PlayerConfig : EntityTypeConfiguration<Player>
{
public PlayerConfig()
{
// For TPH
this.Map(m => m.Requires(discriminator: "PersonType").HasValue(2));
}
}
}

در اینجا توسط متد Map، نام فیلد discriminator به PersonType تغییر کرده. همچنین چون مقدار پیش فرض تعیین شده توسط متد HasValue عددی است، نوع این فیلد در سمت بانک اطلاعاتی به int null تغییر می‌کند.


ب) Table per Type یا TPT

در حالت TPT، به ازای هر کلاس موجود در سلسله مراتب تعیین شده، یک جدول در سمت بانک اطلاعاتی تشکیل می‌گردد.
در جداول متناظر با Sub classes، تنها همان فیلدهایی وجود خواهند داشت که در کلاس‌های هم نام وجود دارد و فیلدهای کلاس پایه در آن‌ها ذکر نخواهد گردید. همچنین این جداول دارای یک Primary key نیز خواهند بود (که دقیقا همان کلید اصلی جدول پایه است که به آن Shared primary key هم گفته می‌شود). این کلید اصلی، به عنوان کلید خارجی اشاره کننده به کلاس یا جدول پایه نیز تنظیم می‌گردد:


برای تنظیم این نوع ارث بری، تنها کافی است ویژگی Table را بر روی Sub classes قرار داد:

using System.ComponentModel.DataAnnotations;

namespace EF_Sample05.DomainClasses.Models
{
[Table("Coaches")]
public class Coach : Person
{
public string TeamName { set; get; }
}
}

using System.ComponentModel.DataAnnotations;

namespace EF_Sample05.DomainClasses.Models
{
[Table("Players")]
public class Player : Person
{
public int Number { get; set; }
public string Description { get; set; }
}
}

یا اگر حالت Fluent API را ترجیح می‌دهید، همانطور که در قسمت‌های قبل نیز ذکر شد، معادل ویژگی Table در اینجا، متد ToTable است.

ج) Table per Concrete type یا TPC

در تعاریف ارث بری که تاکنون بررسی کردیم، مرسوم است کلاس پایه را از نوع abstract تعریف کنند. به این ترتیب هدف اصلی، Sub classes تعریف شده خواهند بود؛ چون نمی‌توان مستقیما وهله‌ای را از کلاس abstract تعریف شده ایجاد کرد.
در حالت TPC، به ازای هر sub class غیر abstract، یک جدول ایجاد می‌شود. هر جدول نیز حاوی فیلدهای کلاس پایه می‌باشد (برخلاف حالت TPT که جداول متناظر با کلاس‌های مشتق شده، تنها حاوی همان خواص و فیلدهای کلاس‌های متناظر بودند و نه بیشتر). به این ترتیب عملا جداول تشکیل شده در بانک اطلاعاتی، از وجود ارث بری در سمت کدهای ما بی‌خبر خواهند بود.


برای پیاده سازی TPC نیاز است از Fluent API استفاده شود:

using System.ComponentModel.DataAnnotations;
using System.Data.Entity.ModelConfiguration;
using EF_Sample05.DomainClasses.Models;

namespace EF_Sample05.DataLayer.Mappings
{
public class PersonConfig : EntityTypeConfiguration<Person>
{
public PersonConfig()
{
// for TPC
this.Property(x => x.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
}

using System.Data.Entity.ModelConfiguration;
using EF_Sample05.DomainClasses.Models;

namespace EF_Sample05.DataLayer.Mappings
{
public class CoachConfig : EntityTypeConfiguration<Coach>
{
public CoachConfig()
{
// For TPH
//this.Map(m => m.Requires(discriminator: "PersonType").HasValue(1));

// for TPT
//this.ToTable("Coaches");

//for TPC
this.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Coaches");
});
}
}
}

using System.Data.Entity.ModelConfiguration;
using EF_Sample05.DomainClasses.Models;

namespace EF_Sample05.DataLayer.Mappings
{
public class PlayerConfig : EntityTypeConfiguration<Player>
{
public PlayerConfig()
{
// For TPH
//this.Map(m => m.Requires(discriminator: "PersonType").HasValue(2));

// for TPT
//this.ToTable("Players");

//for TPC
this.Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Players");
});
}
}
}

ابتدا نوع فیلد Id از حالت Identity خارج شده است. این مورد جهت کار با TPC ضروری است در غیراینصورت EF هنگام ثبت، به مشکل بر می‌خورد، از این لحاظ که برای دو شیء، به یک Id خواهد رسید و امکان ثبت را نخواهد داد. بنابراین در یک چنین حالتی استفاده از نوع Guid برای تعریف primary key شاید بهتر باشد. بدیهی است در این حالت باید Id را به صورت دستی مقدار دهی نمود.
در ادامه توسط متد MapInheritedProperties، به همان مقصود لحاظ کردن تمام فیلدهای ارث بری شده در جدول حاصل، خواهیم رسید. همچنین نام جداول متناظر نیز ذکر گردیده است.


سؤال : از این بین، بهتر است از کدامیک استفاده شود؟

- برای حالت‌های ساده از TPH استفاده کنید. برای مثال یک بانک اطلاعاتی قدیمی دارید که هر جدول آن 200 تا یا شاید بیشتر فیلد دارد! امکان تغییر طراحی آن هم وجود ندارد. برای اینکه بتوان به حس بهتری حین کارکردن با این نوع سیستم‌های قدیمی رسید، می‌شود از ترکیب TPH و ComplexTypes (که در قسمت‌های قبل در مورد آن بحث شد) برای مدیریت بهتر این نوع جداول در سمت کدهای برنامه استفاده کرد.
- اگر علاقمند به استفاده از روابط پلی‌مرفیک هستید ( برای مثال در کلاسی دیگر، ارجاعی به کلاس پایه Person وجود دارد) و sub classes دارای تعداد فیلدهای کمی هستند، از TPH استفاده کنید.
- اگر تعداد فیلدهای sub classes زیاد است و بسیار بیشتر است از کلاس پایه، از روش TPT استفاده کنید.
- اگر عمق ارث بری و تعداد سطوح تعریف شده بالا است، بهتر است از TPC استفاده کنید. حالت TPT از join استفاده می‌کند و حالت TPC از union برای تشکیل کوئری‌ها کمک خواهد گرفت
مطالب
الگوی استخر اشیاء Object Pool Pattern
الگوی استخر اشیاء، جزو الگوهای تکوینی است و کار آن جلوگیری از ایجاد اشیاء تکراری و محافظت از به هدر رفتن حافظه است. نحوه کار این الگو بدین شکل است که وقتی کاربر درخواست نمونه‌ای از یک شیء را می‌دهد، بعد از اتمام کار، شیء نابود نمی‌شود؛ بلکه به استخر بازگشت داده می‌شود تا در درخواست‌های آینده، مجددا مورد استفاده قرار گیرد. این کار موجب عدم هدر رفتن حافظه و همچنین بالا رفتن کارآیی برنامه می‌گردد. این الگو به خصوص برای اشیایی که مدت کوتاهی مورد استفاده قرار میگیرند و آماده سازی آن‌ها هزینه بر است بسیار کارآمد می‌باشد. از آنجا که هزینه‌ی ساخت و نابود سازی در حد بالایی قرار دارد و آن شیء به طور مکرر مورد استفاده قرار می‌گیرد، زمان زیادی صرفه جویی می‌شود.

در این الگو ابتدا شیء از استخر درخواست می‌شود. اگر قبلا ایجاد شده باشد، مجددا مورد استفاده قرار می‌گیرد. در غیر این صورت نمونه جدیدی ایجاد می‌شود و وقتی که کار آن پایان یافت به استخر بازگشت داده شده و نگهداری می‌شود، تا زمانی که مجددا درخواست استفاده از آن برسد.
 یکی از نکات مهم و کلیدی این است که وقتی کار شیء مربوطه تمام شد، باید اطلاعات شیء قبلی و داده‌های آن نیز پاکسازی شوند؛ در غیر این صورت احتمال آسیب و خطا در برنامه بالا می‌رود و این الگو را به یک ضد الگو تبدیل خواهد کرد.
نمونه‌ای از پیاده سازی این الگو را در دات نت، می‌توانید در data provider‌های مخصوص SQL Server نیز ببینید. از آنجا که ایجاد اتصال به دیتابیس، هزینه بر بوده و دستورات در کوتاه‌ترین زمان ممکن اجرا می‌شوند، این کانکشن‌ها یا اتصالات بعد از بسته شدن از بین نمی‌روند، بلکه در استخر مانده تا زمانیکه مجددا نمونه مشابهی از آن‌ها درخواست شود تا دوباره مورد استفاده قرار بگیرند تا از هزینه اولیه برای ایجاد آن‌ها پرهیز شود. استفاده از این الگو در برنامه نویسی با سوکت ها، تردها و کار با اشیاء گرافیکی بزرگ مثل فونت‌ها و تصاویر Bitmap کمک شایانی می‌کند. ولی در عوض برای اشیای ساده می‌تواند کارآیی را به شدت کاهش دهد.

الگوی بالا را در سی شارپ بررسی می‌کنیم:
ابتدا کلاس PooledObject را به عنوان یک شیء بزرگ و پر استفاده ایجاد می‌کنیم:
 public class PooledObject
    {
        DateTime _createdAt = DateTime.Now;

        public DateTime CreatedAt
        {
            get { return _createdAt; }
        }

        public string TempData { get; set; }

        public void DoSomething(string name)
        {
            Console.WriteLine($"{name} : {TempData} is written on {CreatedAt}");
        }
    }
tempdata ویژگی است که باید برای هر شیء، مجزا باشد. پس باید دقت داشت برای استفاده‌های بعدی نیاز است پاک سازی شود.
بعد از آن کلاس پول را پیاده سازی می‌کنیم:
public static class Pool
{
    private static List<PooledObject> _available = new List<PooledObject>();
    private static List<PooledObject> _inUse = new List<PooledObject>();
 
    public static PooledObject GetObject()
    {
        lock(_available)
        {
            if (_available.Count != 0)
            {
                PooledObject po = _available[0];
                _inUse.Add(po);
                _available.RemoveAt(0);
                return po;
            }
            else
            {
                PooledObject po = new PooledObject();
                _inUse.Add(po);
                return po;
            }
        }
    }
 
    public static void ReleaseObject(PooledObject po)
    {
        CleanUp(po);
 
        lock (_available)
        {
            _available.Add(po);
            _inUse.Remove(po);
        }
    }
 
    private static void CleanUp(PooledObject po)
    {
        po.TempData = null;
    }
}
در کلاس بالا، کاربر با متد GetObject، درخواست شی‌ءایی را می‌کند و متد نگاه می‌کند که اگر لیست موجودی، پر باشد، اولین نمونه‌ی در دسترس را ارسال می‌کند. ولی در صورتیکه نمونه‌ای از آن نباشد، یک نمونه‌ی جدید را ایجاد کرده و آن را در لیست مورد استفاده‌ها قرار می‌دهد و به کاربر باز می‌گرداند.
متد Release Object وظیفه‌ی بازگرداندن شیء را به استخر، دارد که از لیست در حال استفاده‌ها آن را حذف کرده و به لیست موجودی اضافه می‌کند. متد Cleanup در این بین وظیفه ریست کردن شیء را دارد تا مشکلی که در بالا بیان کردیم رخ ندهد.
کد زیر را اجرا می‌کنیم:
            var obj1 = Pool.GetObject();
            obj1.DoSomething("obj1");

            Thread.Sleep(2000);
            var obj2 = Pool.GetObject();
            obj2.DoSomething("obj2");
            Pool.ReleaseObject(obj1);

            Thread.Sleep(2000);
            var obj3 = Pool.GetObject();
            obj3.DoSomething("obj3");
نتیجه به شکل زیر است:
obj1 :  is written on 4/21/2016 11:25:26 AM
obj2 :  is written on 4/21/2016 11:25:28 AM
obj3 :  is written on 4/21/2016 11:25:26 AM
ابتدا شیء obj1 ایجاد می‌شود و سپس obj2 و بعد از آن obj1 به لیست موجودی‌ها بازگشته و برای obj3 همان شیء را بازگشت می‌هد که برای obj1 ساخته بود. توقف تردها در این مثال برای مشاهده‌ی بهتر زمان است.
مطالب
بررسی Bad code smell ها: میراث رد شده

میراث رد شده یا Refused bequest به دسته «بد استفاده کنندگان از شیء گرایی» تعلق دارد. این دسته از کدهای بد بو، معمولا استفاده ناقص یا نادرستی از مفاهیم و اصول شیء گرایی دارند. 
زمانیکه یک کلاس تنها بخشی از اعضای (خصوصیت، متد و ...) کلاس پدر خود را استفاده می‌کند، با این الگو سر و کار داریم. در چنین شرایطی دیگر اعضای کلاس پدر یا استفاده نمی‌شوند و یا حتی در صورت پیاده سازی شدن توسط کلاس، بلااستفاده می‌مانند. به طور مثال متدهایی از کلاس پدر پیاده سازی می‌شوند و با پرتاب یک استثناء در بدنه‌شان از کار می‌افتند. 
یکی از دلایل مهم ایجاد چنین کدهای بد بویی، ایجاد رابطه ارث بری تنها برای استفاده دوباره از کدهای یک کلاس است. در صورتیکه ممکن است کلاس پدر و فرزند هیچ ارتباط منطقی ای از نظر ارث بری با یکدیگر نداشته باشند.   
به طور مثال فرض کنید در حال توسعه یک محصول هستید که در آن فروش کالا اتفاق می‌افتد. در ابتدای کار، تنها کاربران این محصول، شرکت‌ها هستند. روالی نیز برای محاسبه تخفیف مربوط به شرکت‌ها ایجاد شده است. در این روال یک تخفیف پایه وجود دارد که به همه مشتریان تعلق می‌گیرید و تخفیف‌هایی نیز وجود دارند که به هر یک از شرکت‌ها تعلق می‌گیرند. میزان تخفیف نهایی برای یک شرکت از مجموع این دو مقدار بدست می‌آید. کلاس مربوط به محاسبه تخفیف به این صورت است: 

public class DiscountCalculator 
{ 
    protected decimal CalculateGeneralDiscount() 
    { 
        // calculate general discount 
        return 0; 
    } 
    protected decimal AddSpecificDiscount(decimal baseDiscount) 
    { 
        // add specific discounts to base discount 
        return 0; 
    } 
    protected virtual decimal GetFinalDiscount() 
    { 
        var baseDiscount = CalculateGeneralDiscount(); 
        var addedDiscount = AddSpecificDiscount(baseDiscount); 
        return addedDiscount; 
    } 
}
بعد از مدتی نیاز می‌شود که افراد حقیقی از نرم افزار استفاده کرده و خرید نمایند و این مکانیزم تخفیف برای آن‌ها نیز اعمال شود. توسعه دهنده بعد از بررسی به این نتیجه می‌رسد که تنها تفاوت این مکانیزم با مکانیزم قبلی، متد AddSpecificDiscount است که باید برای اشخاص حقیقی بازنویسی شود. این توسعه دهنده تصمیم می‌گیرد برای استفاده دوباره از کد موجود در کلاس DiscountCalculator، کلاس مربوط به اشخاص حقیقی را از آن ارث ببرد. که نتیجه به صورت زیر خواهد بود:
public class PersonDiscountCalculator : DiscountCalculator 
{ 
    private decimal AddSpecificDiscountForPerson(decimal baseDiscount) 
    { 
        // calculate base discount for person 
        return 0; 
    } 
    protected override decimal GetFinalDiscount() 
    { 
        var baseDiscount = CalculateGeneralDiscount(); 
        var added = AddSpecificDiscountForPerson(baseDiscount); 
        return added; 
    } 
}

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

روش‌های اصلاح این نوع کد بد بو 

1) زمانیکه رابطه ارث بری هیچ معنایی ندارد، می‌توان به جای استفاده از ارث بری، شیء مربوط به کلاس پدر را ایجاد و در بدنه کلاس فرزند از آن استفاده کرد. مثلا برای فراخوانی متدها یا دسترسی به خصوصیت‌ها (مثال ذکر شده در این دسته نیست).
2) زمانیکه رابطه منطقی وجود داشته باشد، ولی اعضای اضافی کلاس پدر، به فرزند به ارث برسند، راه حل معمولا در جدا کردن کلاس پدر و ایجاد یک کلاس جدید پدر برای مصرف مورد نظر است.  
در مثال مطرح شده رابطه منطقی بین کلاس‌ها وجود دارد؛ ولی نه به شکلی که پیاده سازی شده است. یکی از راه‌های مناسب برای رفع چنین مشکلی، ایجاد یک کلاس پدر مشترک (در اینجا DiscountCalculator) و انتقال منطق‌های مربوطه به آن و ارث بری کردن تک تک کلاسها از آن است.  
public abstract class DiscountCalculator 
{ 
    protected decimal CalculateGeneralDiscount() 
    { 
        // calculate general discount 
        return 0; 
    } 
    protected abstract decimal AddSpecificDiscount(decimal baseDiscount); 
    protected virtual decimal GetFinalDiscount() 
    { 
        var baseDiscount = CalculateGeneralDiscount(); 
        var addedDiscount = AddSpecificDiscount(baseDiscount); 
        return addedDiscount; 
    } 
}

کلاس DiscountCalculator به عنوان کلاس پایه برای محاسبات تخفیف تعریف شده و کلاس‌های مربوط به شرکت و شخص از آن ارث بری می‌کنند. به این صورت که محاسبات کلی تخفیف‌ها در کلاس پایه و محاسبات مربوط به افزودن تخفیف‌های خاص در کلاس‌های فرزند انجام می‌شود (با فرض این که محاسبات مربوط به افزودن تخفیف‌های خاص تفاوت دارند).   
public class CompanyDiscountCalculator: DiscountCalculator 
{ 
    protected override decimal AddSpecificDiscount(decimal baseDiscount) 
        { 
            // add some customer specific discounts to base discount 
            return 0; 
        } 
    } 
    public class PersonDiscountCalculator : DiscountCalculator 
    { 
        protected override decimal AddSpecificDiscount(decimal baseDiscount) 
        { 
            // calculate base discount for person 
            return 0; 
        } 
}

جمع بندی 

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

مطالب
اشیاء تغییر ناپذیر (Immutable Object)
کلمه‌ی mutable به معنای تغییر پذیر و کلمه‌ی immutable به معنای تغیر ناپذیر در زبان انگلیسی تعریف شده‌اند. در دنیای IT این دو واژه نیز همین معنا را دارند. بطور مثال: یک رشته‌ی mutable، یعنی رشته‌ای که بتوان آن را تغییر داد و یک رشته‌ی immutable یعنی رشته‌ای که غیر قابل تغییر است.



در حین مطالعه‌ی منابع مختلف درباره‌ی موضوع این مطلب، جمله‌ای را با این مضمون دیدم: برای ساخت کوزه، گل را تا مرطوب هست باید شکل داد. زمانیکه گل خشک شود، دیگر نمی‌توان کوزه را تغییر شکل داد. اشیاء تغییر ناپذیر هم به همین شکل هستند. بعد از ایجاد این اشیاء، دیگر نمی‌توان به هیچ وجه آنها را تغییر داد.

تعریف اشیاء تغییر ناپذیر (Immutable Objects) :
این اشیاء، اشیائی هستند که بعد از بارگزاری در حافظه، به هیچ وجه نمی‌توانند اصلاح و یا تغییر کنند. نه از طریق خارجی (کاربران External) و نه از طریق داخلی (اعضای کلاس Internal).

چه زمانی از این اشیاء استفاده می‌کنیم؟
اشیاء تغییر ناپذیر برای داده‌های استاتیک استفاده می‌شوند و نمونه‌هایی از آن در بخش زیر لیست شده‌اند:

 • داده‌های اصلی (Master Data): یکی از بیشترین کاربرد‌های اشیاء تغییر ناپذیر، برای بارگذاری داده‌های اصلی است (کشور‌ها، واحد‌های پولی، استان ها) و داده‌هایی که به ندرت تغییر می‌کنند. این داده‌های اصلی بعد از بارگزاری در حافظه، دیگر تغییر نخواهند کرد.

 • اطلاعات پیکره‌بندی (Configuration Data): همه‌ی برنامه‌ها نیاز به اطلاعات پیکره‌بندی دارند. در دنیای برنامه‌های مایکروسافت، عموما این اطلاعات پیکره بندی را در فایل‌های web.config و App.config ذخیره می‌کنیم. این نوع اطلاعات بصورت یک شیء در حافظه بارگذاری می‌شوند و بعدا تغییر نخواهند کرد.

 • اشیاء Singleton: اشیاء singleton اشیائی هستند که تنها یک نمونه از آنها را می‌توان ایجاد کرد. در برنامه‌ها از این اشیاء برای اشتراک گذاشتن اطلاعات استاتیک استفاده می‌کنند. اگر این اطلاعات تغییر نکنند، یکی از گزینه‌ها، استفاده از اشیاء تغییر ناپذیر هستند.

چگونه می‌توان در سی شارپ اشیاء تغییر ناپذیر را ایجاد کنیم؟

اشیاء تغییر ناپذیر (immutable objects) تنها توسط کلاس‌های تغییر ناپذیر (immutable classes) می‌توانند ایجاد شوند.
برای ایجاد کلاسی تغییر ناپذیر، سه مرحله باید طی شود:
 1- حذف بلاک Set: همانطور که گفته شد، بخش Set از property ‌ها باید حذف شود. با حذف این بخش بعد از بارگزاری شیء در حافظه، دیگر نمی‌توان آن را تغییر داد:
public class Currency
{
  private string _currencyName;
  private string _countryName;

  public string CurrencyName
  {
     get { return _currencyName; }
  }

  public string CountryName
  {
     get { return _countryName; }
  }
}

 2- مهیا کردن پارامتر‌ها از طریق سازنده‌ی کلاس: با حذف بلاک set، راهی برای بارگزاری اطلاعات، در کلاس وجود ندارد. از این رو می‌توان از طریق پارامتر‌های سازنده‌ی کلاس، اطلاعات را به شیء ارسال کرد.
  private string _currencyName;
  private string _countryName;
  public Currency(string paramCurrencyName,string paramCountryName)
  {
     _currencyName= paramCurrencyName;
     _countryName = paramCountryName;
  }

 3- تعریف متغیر‌های کلاس به صورت فقط خواندنی READONLY
در تعریف اولیه گفته شد که اشیاء immutable نه از طریق خارجی (کاربر) و «کمی فراتر» نه از طریق داخلی (اعضای کلاس) قابل تغییر نیستند. اما کلاس ایجاد شده را می‌توان بعد از ایجاد نمونه‌ای از آن، مجددا تغییر داد. کافی است یک متد به شکل زیر در آن تعریف کنیم و به‌راحتی وضعیت شیء را از طریق آن تغییر دهیم.
  public void DoSomthing()
  {
     _countryName = "somthing else";
  }

راه حل ارائه شده‌ی برای حل این موضوع، معرفی متغیر‌ها به صورت readonly می‌باشد. متغیرهایی که بصورت فقط خواندنی تعریف می‌شوند، تنها از طریق سازنده‌ی شیء می‌توانند مقداردهی اولیه شوند.
باز طراحی نهایی کلاس Currency  به صورت زیر است:
 public class Currency
{
  private readonly string _currencyName;
  private readonly string _countryName;
  public string CurrencyName
  {
    get { return _currencyName; }
  }

  public string CountryName
  {
    get { return _countryName; }
  }
  public Currency(string paramCurrencyName,string paramCountryName)
  {
     _currencyName= paramCurrencyName;
     _countryName = paramCountryName;
  }
}
مطالب
React 16x - قسمت 5 - کامپوننت‌ها - بخش 2 - نمایش لیست‌ها و مدیریت رویدادها و حالات
در قسمت قبل، اولین کامپوننت React خود را ایجاد کردیم و سپس جزئیات بیشتری از عبارات JSX را مانند نحوه‌ی تعریف المان‌های مختلف و تنظیم مقادیر ویژگی‌های آن‌را بررسی کردیم. در ادامه‌ی همان مثال، در این قسمت، نحوه‌ی نمایش لیست‌ها و تعریف و مدیریت رویدادها را در کامپوننت‌های React، بررسی می‌کنیم.


نحوه‌ی رندر لیستی از اشیاء در کامپوننت‌های React

فرض کنید می‌خواهیم لیستی از تگ‌ها را رندر کنیم. برای این منظور ابتدا داده‌های مرتبط را به خاصیت state کامپوننت، اضافه می‌کنیم:
class Counter extends Component {
  state = {
    count: 0,
    tags: ["tag 1", "tag 2", "tag 3"]
  };
اکنون می‌خواهیم tags را توسط المان‌های ul و ui رندر کنیم. اگر با Angular کار کرده باشید، به همراه یک دایرکتیو ngFor است که توسط آن می‌توان یک حلقه را در قالب جاری، پیاده سازی و رندر کرد. اما در React و عبارات JSX، چیزی به نام مفهوم حلقه‌ها وجود خارجی ندارد؛ چون JSX یک templating engine نیست. فقط بیان ساده‌ی المان‌هایی است که قرار است توسط کامپایلر Babel به کدهای جاوا اسکریپتی ترجمه شوند. بنابراین اکنون این سؤال وجود دارد که چگونه می‌توان لیستی از عناصر را در اینجا رندر کرد؟
در مطلب «React 16x - قسمت 3 - بررسی پیشنیازهای جاوا اسکریپتی - بخش 2» در مورد متد Array.map بحث شد. در اینجا می‌توان توسط متد map، هر المان آرایه‌ی تگ‌ها را به یک المان React تبدیل و سپس رندر کرد:
class Counter extends Component {
  state = {
    count: 0,
    tags: ["tag 1", "tag 2", "tag 3"]
  };

  render() {
    return (
      <div>
        <span className={this.getBadgeClasses()}>{this.formatCount()}</span>
        <button className="btn btn-secondary btn-sm">Increment</button>
        <ul>
          {this.state.tags.map(tag => (
            <li>{tag}</li>
          ))}
        </ul>
      </div>
    );
  }
در این مثال، داخل المان ul، با یک {} شروع می‌کنیم تا بتوان به صورت پویا به مقدار آرایه‌ی this.state.tags دسترسی پیدا کرد. سپس متد map را بر روی این آرایه فراخوانی می‌کنیم. متد map، هر عضو آرایه‌ی tags را به callback function آن ارسال کرده و خروجی آن‌را به صورت یک عبارت JSX که در نهایت به یک المان جاوا اسکریپتی خالص ترجمه خواهد شد، تبدیل می‌کند. این فرآیند سبب رندر لیست tags می‌شود:


هرچند اکنون لیستی از تگ‌ها در مرورگر رندر شده‌اند، اما در کنسول توسعه دهندگان مرورگر، یک اخطار نیز درج شده‌است. علت اینجا است که React نیاز دارد تا بتواند هر آیتم رندر شده را به صورت منحصربفردی شناسایی کند. هدف این است که بتواند در صورت تغییر state هر المان در DOM مجازی خودش، خیلی سریع تشخیص دهد که چه چیزی تغییر کرده و فقط کدام قسمت خاص را باید در DOM اصلی، درج و به روز رسانی کند. برای رفع این مشکل، ویژگی key را به هر المان li در کدهای فوق اضافه می‌کنیم:
<li key={tag}>{tag}</li>
البته در مثال ما تگ‌ها منحصربفرد هستند؛ بنابراین استفاده‌ی از آن‌ها به عنوان key، مشکلی را ایجاد نمی‌کند. در یک برنامه‌ی مفصل‌تر، تگ‌ها می‌توانند شیء بوده و هر شیء دارای خاصیت id باشد که در این حالت فرضی می‌توان از tag.id به عنوان key استفاده کرد. همچنین باید دانست که این key فقط نیاز است در لیست ul، منحصربفرد باشد و نیازی نیست تا در کل DOM منحصربفرد باشد.


رندر شرطی عناصر در کامپوننت‌های React

در اینجا می‌خواهیم اگر تگی وجود نداشت، پیام متناسبی ارائه شود؛ در غیراینصورت لیست تگ‌ها همانند قبل نمایش داده شود (رندر شرطی یا conditional rendering). برای انجام اینکار در React، برخلاف Angular، دارای دایرکتیوهای ساختاری if/else نیستیم؛ چون همانطور که عنوان شد، JSX یک templating engine نیست. به همین جهت برای رندر شرطی المان‌ها در React، باید از همان جاوا اسکریپت خالص کمک بگیریم:
  renderTags() {
    if (this.state.tags.length === 0) {
      return <p>There are no tags!</p>;
    }

    return (
      <ul>
        {this.state.tags.map(tag => (
          <li key={tag}>{tag}</li>
        ))}
      </ul>
    );
  }
یک روش حل این مساله، نوشتن متدی است که به همراه یک if/else است. در اینجا اگر آرایه‌ی تگ‌ها، دارای عنصری نبود، یک پاراگراف متناظر نمایش داده می‌شود، در غیراینصورت همان قسمت رندر لیست تگ‌ها را که توسعه دادیم، بازگشت می‌دهیم. بنابراین این متد، دو خروجی JSX را بسته به شرایط مختلف می‌تواند داشته باشد. سپس از این متد به صورت {()this.renderTags} در متد render اصلی استفاده می‌کنیم:
  render() {
    return (
      <div>
        <span className={this.getBadgeClasses()}>{this.formatCount()}</span>
        <button className="btn btn-secondary btn-sm">Increment</button>
        {this.renderTags()}
      </div>
    );
  }
برای آزمایش آن هم یکبار آرایه‌ی tags را به نحو زیر خالی کنید:
  state = {
    count: 0,
    tags: []
  };

روش دوم حل این نوع مساله‌ها، استفاده از روش زیر است؛ در این حالت خاص، فقط یک if را داریم، بدون وجود قسمت else:
{this.state.tags.length === 0 && "Please create a new tag!"}
ابتدا شرط مدنظر نوشته می‌شود، سپس پیامی را که باید در این حالت ارائه شود، پس از && می‌نویسیم. در مثال فوق اگر آرایه‌ی tags خالی باشد، پیامی نمایش داده می‌شود.
اما این روش چگونه کار می‌کند؟! در اینجا && را به دو مقدار مشخص اعمال کرده‌ایم. یکی حاصل یک مقایسه است و دیگری یک مقدار رشته‌ای مشخص. در جاوا اسکریپت برخلاف سایر زبان‌های برنامه نویسی، می‌توان && را بین دو مقدار غیر Boolean نیز اعمال کرد. در جاوا اسکریپت، یک رشته‌ی خالی به false تعبیر می‌شود و اگر تنها دارای یک حرف باشد، true درنظر گرفته می‌شود. برای نمونه در ترکیب 'true && 'Hi، هر دو قسمت به true تفسیر می‌شوند. در این حالت موتور جاوا اسکریپت، دومین عبارت (آخرین عبارت && شده) را بازگشت می‌دهد. همچنین در جاوا اسکریپت عدد صفر به false تفسیر می‌شود. بنابراین ترکیب true && 'Hi' && 1 مقدار 1 را بازگشت می‌دهد؛ چون عدد 1 هم از دیدگاه جاوا اسکریپت به true تفسیر خواهد شد.


مدیریت رخ‌دادها در React


همانطور که در تصویر فوق نیز مشاهده می‌کنید، رخ‌دادهای استاندارد DOM، دارای خواص معادل React ای نیز هستند. برای مثال زمانیکه می‌نویسیم onClick، دقیقا متناظر است با یک خاصیت المان React در عبارات JSX. بنابراین این نام‌ها حساس به کوچکی و بزرگی حروف نیز هستند.
روش تعریف متدهای رخ‌دادگردان در اینجا، با ذکر فعل handle شروع می‌شود:
  handleIncrement() {
    console.log("Increment clicked!");
  }
سپس ارجاعی از این متد را (نه فراخوانی آن‌را)، به خاصیت برای مثال onClick ارسال می‌کنیم:
<button
    onClick={this.handleIncrement}
    className="btn btn-secondary btn-sm"
>
    Increment
</button>
اگر دقت کنید، onClick، ارجاع this.handleIncrement را دریافت کرده‌است (یعنی بدون () ذکر شده‌است) و نه فراخوانی این متد را (با ذکر ()).
اکنون اگر این فایل را ذخیره کرده و خروجی را در مرورگر بررسی کنیم، با هربار کلیک بر روی دکمه‌ی Increment، یک console.log صورت می‌گیرد.

در ادامه می‌خواهیم در این رخ‌دادگردان، مقدار this.state.count را افزایش دهیم. برای این منظور ابتدا مقدار this.state.count را به نحو زیر لاگ می‌کنیم:
  handleIncrement() {
    console.log("Increment clicked!", this.state.count);
  }
پس از ذخیره‌ی فایل و اجرای برنامه، اینبار با کلیک بر روی دکمه‌ی Increment، بلافاصله خطای «Uncaught TypeError: Cannot read property 'state' of undefined» در کنسول توسعه دهنده‌های مرورگر ظاهر می‌شود. عنوان می‌کند که شیء this در این متد، undefined است؛ بنابراین امکان خواندن خاصیت state از آن وجود ندارد.


bind مجدد شیء this در رخ‌دادگردان‌های React

در مورد this و bind مجدد آن در مطلب «React 16x - قسمت 2 - بررسی پیشنیازهای جاوا اسکریپتی - بخش 1» مفصل بحث کردیم و در اینجا می‌خواهیم از نتایج آن استفاده کنیم.
همانطور که مشاهده کردید، در متد رویدادگران handleIncrement، به شیء this دسترسی نداریم. چرا؟ چون this در جاوا اسکریپت نسبت به سایر زبان‌های برنامه نویسی، متفاوت رفتار می‌کند. بسته به اینکه یک متد یا تابع، چگونه فراخوانی می‌شود، this می‌تواند اشیاء متفاوتی را بازگشت دهد. اگر تابعی به عنوان یک متد و جزئی از یک شیء فراخوانی شود، this در این حالت همواره ارجاعی را به آن شیء باز می‌گرداند. اما اگر آن تابع به صورت متکی به خود فراخوانی شد، به صورت پیش‌فرض ارجاعی را به شیء سراسری window مرورگر، بازگشت می‌دهد و اگر strict mode فعال باشد، تنها undefined را بازگشت می‌دهد. به همین جهت است که در اینجا خطای undefined بودن this را دریافت می‌کنیم.
یک روش حل این مشکل که پیشتر نیز در مورد آن توضیح دادیم، استفاده از متد bind است:
  constructor() {
    super();
    console.log("constructor", this);
    this.handleIncrement = this.handleIncrement.bind(this);
  }
زمانیکه شیءای از نوع کلاس جاری ایجاد می‌شود، متد constructor آن نیز فراخوانی خواهد شد. در این مرحله دسترسی کاملی به شیء this وجود دارد که نمونه‌ی آن‌را با console.log نوشته شده می‌توانید آزمایش کنید. در اینجا چون کامپوننت جاری از کلاس Component مشتق شده‌است، پیش از دسترسی به شیء this، نیاز است سازنده‌ی کلاس پایه توسط متد super فراخوانی شود. اکنون که به this دسترسی داریم، می‌توان توسط متد bind، مقدار شیء this شیءای دیگر مانند this.handleIncrement را تنظیم مجدد کنیم (متدها نیز در جاوا اسکریپت شیء هستند). خروجی آن، یک وهله‌ی جدید از شیء handleIncrement است که this آن اینبار به وهله‌ای از شیء جاری اشاره می‌کند. به همین جهت خروجی آن‌را به this.handleIncrement انتساب می‌دهیم تا مشکل تعریف نشده بودن this آن برطرف شود.
اکنون اگر برنامه را اجرا کنید، با کلیک بر روی دکمه‌ی Increment، بجای this.state.count لاگ شده، مقدار آن که صفر است، در کنسول توسعه دهنده‌های مرورگر ظاهر می‌شود.


این یک روش است که کار می‌کند؛ اما کمی طولانی است و به ازای هر روال رویدادگردانی باید دقیقا به همین نحو تکرار شود. روش دیگر، تبدیل متد handleIncrement به یک arrow function است و همانطور که در قسمت دوم این سری نیز بررسی کردیم، arrow functionها، this شیء جاری را بازنویسی نمی‌کنند؛ بلکه آن‌را به ارث می‌برند. بنابراین ابتدا کدهای سازنده‌ی فوق را حذف می‌کنیم (چون دیگر نیازی به آن‌ها نیست) و سپس متد handleIncrement سابق را به صورت زیر، تبدیل به یک arrow function می‌کنیم:
  handleIncrement = () => {
    console.log("Increment clicked!", this.state.count);
  }
به این ترتیب با کلیک بر روی دکمه‌ی Increment، مجددا همان خروجی تصویر قبلی را دریافت می‌کنیم؛ این روش ساده‌تر و تمیزتر است و نیازی به rebind دستی تک تک رویدادگردان‌های کامپوننت جاری در این حالت وجود ندارد.


به روز رسانی state در کامپوننت‌های React

اکنون که در روال رویدادگردان handleIncrement به شیء this و سپس مقدار this.state.count آن دسترسی پیدا کرده‌ایم، می‌خواهیم با هربار کلیک بر روی این دکمه، یک واحد مقدار آن‌را افزایش داده و در UI نمایش دهیم.
در React، خواص شیء state را جهت نمایش آن‌ها در UI، مستقیما تغییر نمی‌دهیم. به عبارت دیگر نوشتن یک چنین کدی در React برای به روز رسانی UI، مرسوم نیست:
  handleIncrement = () => {
    this.state.count++;
  };
اگر تغییر فوق را اعمال و سپس برنامه را اجرا کنید، با کلیک بر روی دکمه‌ی Increment ... اتفاقی رخ نمی‌دهد! رفتار React با Angular متفاوت است و در اینجا هرچند توسط فراخوانی {()this.formatCount} کار نمایش خاصیت count انجام می‌شود، اما به ظاهر، تغییرات مقدار count، به عبارات JSX متصل نیست. در کامپوننت‌های Angular اگر مقدار خاصیتی را تغییر دهید و اگر این خاصیت در قالب آن کامپوننت، به آن خاصیت bind شده باشد، شاهد به روز رسانی آنی UI خواهید بود (Change Detection آنی و به ازای هر تغییری)؛ اما در React خیر. هرچند در همان Angular هم توصیه می‌شود که از حالت changeDetection: ChangeDetectionStrategy.OnPush برای رسیدن به حداکثر کارآیی نمایشی کامپوننت‌ها استفاده شود؛ حالت OnPush در Angular، به روش تشخیص تغییرات React که در ادامه توضیح داده می‌شود، بیشتر شبیه است.

در کدهای فوق هرچند با کلیک بر روی دکمه‌ی Increment، مقدار count افزایش یافته‌است، اما React از وقوع این تغییرات مطلع نیست. به همین جهت است که هیچ تغییری را در UI برنامه مشاهده نمی‌کنید.
با اجرای قطعه کد فوق، یک چنین اخطاری نیز در کنسول توسعه دهندگان مرورگر ظاهر می‌شود:
  Line 33:5:  Do not mutate state directly. Use setState()  react/no-direct-mutation-state

برای رفع این مشکل باید از یکی از متدهای به ارث برده شده‌ی از کلاس پایه‌ی Component، به نام setState استفاده کرد. به این ترتیب به React اعلام می‌کنیم که state تغییر کرده‌است (فعالسازی Change Detection، فقط در صورت نیاز). سپس React شروع به محاسبه‌ی تغییرات کرده و در نتیجه قسمت‌های متناظری از UI را برای هماهنگ سازی DOM مجازی خودش با DOM اصلی، به روز رسانی می‌کند.
زمانیکه از متد setState استفاده می‌کنیم، شیءای را باید به صورت یک پارامتر به آن ارسال کنیم. در این حالت مقادیر آن یا به خاصیت state جاری اضافه می‌شوند و یا در صورت از پیش موجود بودن، همان خواص را بازنویسی می‌کنند:
  handleIncrement = () => {
    this.setState({ count: this.state.count + 1 });
  };
در اینجا به متد this.setState که از قسمت extends Component جاری به ارث رسیده‌است، یک شیء را با خاصیت count و مقدار جدیدی، ارسال می‌کنیم.
در این مرحله، فایل جاری را ذخیره کرده و پس از بارگذاری مجدد برنامه در مرورگر، بر روی دکمه‌ی Increment کلیک کنید. اینبار ... کار می‌کند! چون React از تغییرات مطلع شده‌است:


وقتی state تغییر می‌کند، چه اتفاقاتی رخ می‌دهند؟

با فراخوانی متد this.setState، به React اعلام می‌کنیم که state یک کامپوننت قرار است تغییر کند. سپس React فراخوانی مجدد متد Render را در صف اجرایی خودش قرار می‌دهد تا در زمانی در آینده، اجرا شود؛ این فراخوانی async است. کار متد render، بازگشت یک المان جدید React است. در اینجا DOM مجازی React از چند المان، به صورت یک div و دو فرزند دکمه و span تشکیل شده‌است. در این حالت یک DOM مجازی قدیمی نیز از قبل (پیش از اجرای مجدد متد render) وجود دارد. در این لحظه، React این دو DOM مجازی را کنار هم قرار می‌دهد و محاسبه می‌کند که در اینجا دقیقا کدام المان‌ها نسبت به قبل تغییر کرده‌اند. برای نمونه در اینجا تشخیص می‌دهد که span است که تغییر کرده، چون مقدار count، توسط آن نمایش داده می‌شود. در این حالت از کل DOM اصلی، تنها همان span تغییر کرده را به روز رسانی می‌کند و نه کل DOM را (و نه اعمال مجدد کل المان‌های حاصل از متد render را).
این مورد را می‌توان به نحو زیر آزمایش و مشاهده کرد:
در مرورگر بر روی المان span که شماره‌ها را نمایش می‌دهد، کلیک راست کرده و گزینه‌ی inspect را انتخاب کنید. سپس بر روی دکمه‌ی Increment کلیک نمائید. مرورگر قسمتی را که به روز می‌شود، با رنگی مشخص و متمایز، به صورت لحظه‌ای نمایش می‌دهد:



ارسال پارامترها به متدهای رویدادگردان

تا اینجا متد handleIncrement، بدون پارامتر تعریف شده‌است. فرض کنید در یک برنامه‌ی واقعی قرار است با کلیک بر روی این دکمه، id یک محصول را نیز به handleIncrement، منتقل و ارسال کنیم. اما در onClick={this.handleIncrement} تعریف شده، یک ارجاع را به متد handleIncrement داریم. بنابراین برای حل این مساله نمی‌توان از روشی مانند onClick={this.handleIncrement(1)} استفاده کرد که در آن عدد فرضی 1 به صورت آرگومان متد handleIncrement ذکر شده‌است.
یک روش حل این مساله، تعریف متد دومی است که متد handleIncrement پارامتر دار را فراخوانی می‌کند:
  doHandleIncrement = () => {
    this.handleIncrement({ id: 1, name: "Product 1" });
  };
و در این حالت برای مثال متد handleIncrement یک شیء را پذیرفته‌است:
  handleIncrement = product => {
    console.log(product);
    this.setState({ count: this.state.count + 1 });
  };
سپس بجای تعریف onClick={this.handleIncrement}، از متد doHandleIncrement استفاده خواهیم کرد؛ یعنی onClick={this.doHandleIncrement}

هرچند این روش کار می‌کند، اما بیش از اندازه طولانی شده‌است. راه حل بهتر، استفاده از یک inline function است:
onClick={() => this.handleIncrement({ id: 1, name: "Product 1" })}
یعنی کل arrow function مربوط به doHandleIncrement را داخل onClick قرار می‌دهیم و چون یک سطری است، نیازی به ذکر {} و سمی‌کالن انتهای آن‌را هم ندارد.


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: sample-04-part02.zip
مطالب
5 دلیل برای استفاده از یک ابزار ORM

چرا باید از ابزارهای Object relational Mapper یا به اختصار ORM استفاده کرد؟ در اینجا سخن در مورد ORM خاصی نیست. هدف تبلیغ یک محصول ویژه هم نمی‌باشد و یک بحث کلی مد نظر است.
کار ابزارهای ORM خواندن ساختار دیتابیس شما بوده و سپس ایجاد کلاس‌هایی بر اساس این ساختار ، برقراری ارتباط بین اشیاء ایجاد شده و جداول، ویووها، رویه‌های ذخیره شده و غیره می‌باشد. همچنین این ابزارها امکان تعریف روابط one-to-one, one-to-many, many-to-one, و many-to-many بین اشیاء را نیز بر اساس ساختار دیتابیس شما فراهم می‌کنند.
در ادامه به فواید استفاده از ORM ها خواهیم پرداخت:

الف) یک ابزار ORM زمان تحویل پروژه را کاهش می‌دهد

اولین و مهم‌ترین دلیلی که بر اساس آن در یک پروژه، استفاده از ORM حائز اهمیت می‌شود، بحث بالا بردن سرعت برنامه نویسی و کاهش زمان تحویل پروژه به مشتری است. این کاهش زمان بسته به نوع پروژه بین 20 تا 50 درصد می‌تواند خود را بروز دهد.
بدیهی است ابزارهای ORM کار شگفت انگیزی را قرار نیست انجام دهند و شما می‌توانید تمام آن عملیات ‌را دستی هم به پایان رسانید؛ اما اجازه دهید یک مثال کوتاه را با هم مرور کنیم.
برای پیاده سازی یک برنامه متداول با حدود 15 تا 20 جدول، حدودا به 30 شیء برای مدل سازی سیستم نیاز خواهد بود و برنامه نویسی این مجموعه بین 5000 تا 10000 سطر کد را به خود اختصاص خواهد داد. بدیهی است برنامه نویسی و آزمایش این سیستم چندین هفته یا ماه به طول خواهد انجامید.
اما با استفاده از یک ORM ، عمده وقت شما به طراحی سیستم و ایجاد ارتباطات بین اشیاء و دیتابیس در طی یک تا دو روز صرف خواهد شد. ایجاد کد بر اساس این مجموعه و با کمک ابزارهای ORM ، آنی است و با چند کلیک صورت می‌گیرد.


ب) یک ابزار ORM کدی با طراحی بهتر را تولید می‌کند

ممکن است شما بگوئید که کد نویسی من بی‌نظیر است و از من بهتر کسی را نمی‌توانید پیدا کنید! به تمامی زوایای کار خود مسلطم و نیازی هم به این‌گونه ابزارها ندارم!
عده‌ای از شما به طور قطع این‌گونه‌اید؛ اما نه همه. در یک تیم متوسط، همه نوع برنامه نویس با سطوح مختلفی را می‌توانید پیدا کنید و تمامی ‌‌آن‌ها برنامه نویس‌ها و یا طراح‌های آنچنان قابلی هم نیستند. بنابراین امکان رسیدن به کدهایی که مطابق اصول دقیق برنامه نویسی شیء گرا نیستند و در آن‌ها الگوهای طراحی به خوبی رعایت نشده، بسیار محتمل است. همچنین در یک تیم زمانیکه از یک الگوی یکسان پیروی نمی‌شود، نتایج نهایی بسیار ناهماهنگ خواهند بود.
در مقابل استفاده از ORM های طراحی شده توسط برنامه نویس‌های قابل (senior (architect level) engineers) ، کدهایی را بر اساس الگوهای استاندارد و پذیرفته شده‌ی شیء‌گرا تولید می‌کنند و همواره یک روند کاری مشخص و هماهنگ را در یک مجموعه به ارمغان خواهند آورد.

ج) نیازی نیست تا حتما یک متخصص دات نت فریم ورک باشید تا از یک ORM استفاده کنید

قسمت دسترسی به داده‌ها یکی از اجزای کلیدی کارآیی برنامه شما است. اگر طراحی و پیاده سازی آن ضعیف باشد، کل برنامه را زیر سؤال خواهد برد. برای طراحی و پیاده سازی دستی این قسمت از کار باید به قسمت‌های بسیاری از مجموعه‌ی دات نت فریم ورک مسلط بود. اما هنگام استفاده از یک ORM مهمترین موردی را که باید به آن تمرکز نمائید بحث طراحی منطقی کار است و ایجاد روابط بین اشیاء و دیتابیس و امثال آن. مابقی موارد توسط ORM انجام خواهد شد و همچنین می‌توان مطمئن بود که پیاده سازی خودکار انجام شده این قسمت‌ها، بر اساس الگوهای طراحی شیء‌گرا است.


د) هنگام استفاده از یک ابزار ORM ، مدت زمان آزمایش برنامه نیز کاهش می‌یابد

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

ه) استفاده از یک ابزار ORM ، کار برنامه نویسی شما را ساده‌تر می‌کند

توضیح این قسمت نیاز به ذکر یک مثال دارد. لطفا به مثال زیر دقت بفرمائید:

try {
Employees objInfo = new Employees();
EmployeesFactory objFactory = new EmployeesFactory();

objInfo.EmployeeID = EmployeeID;
objFactory.Load(objInfo);

// code here to use the "objInfo" object
}
catch(Exception ex) {
// code here to handle the exception
}

به نظر شما کار کردن با یک یا چند شیء تولید شده که نمایانگر ساختار دیتابیس شما هستند و با استفاده از اینترفیس عمومی آن‌ها می‌توان تمامی اعمال بارگذاری، درج و حذف و غیره را انجام داد، ساده‌تر است یا کار کردن با کوهی از دستورات ADO.Net ؟


برداشتی آزاد از Five Reasons for using an ORM Tool