مطالب
تزریق وابستگی (dependency injection) به زبان ساده

این مطلب در ادامه‌ی "آشنایی با الگوی IOC یا Inversion of Control (واگذاری مسئولیت)" می‌باشد که هر از چندگاهی یک قسمت جدید و یا کاملتر از آن ارائه خواهد شد.

==============
به صورت خلاصه ترزیق وابستگی و یا dependency injection ، الگویی است جهت تزریق وابستگی‌های خارجی یک کلاس به آن، بجای استفاده مستقیم از آن‌ها در درون کلاس.
برای مثال شخصی را در نظر بگیرید که قصد خرید دارد. این شخص می‌تواند به سادگی با کمک یک خودرو خود را به اولین محل خرید مورد نظر برساند. حال تصور کنید که 7 نفر عضو یک گروه، با هم قصد خرید دارند. خوشبختانه چون تمام خودروها یک اینترفیس مشخصی داشته و کار کردن با آن‌ها تقریبا شبیه به یکدیگر است، حتی اگر از یک ون هم جهت رسیدن به مقصد استفاده شود، امکان استفاده و راندن آن همانند سایر خودروها می‌باشد و این دقیقا همان مطلبی است که هدف غایی الگوی تزریق وابستگی‌ها است. بجای این‌که همیشه محدود به یک خودرو برای استفاده باشیم، بنابر شرایط، خودروی متناسبی را نیز می‌توان مورد استفاده قرار داد.
در دنیای نرم افزار، وابستگی کلاس Driver ، کلاس Car است. اگر موارد ذکر شده را بدون استفاده از تزریق وابستگی‌ها پیاده سازی کنیم به کلاس‌های زیر خواهیم رسید:

//Person.cs
namespace DependencyInjectionForDummies
{
class Person
{
public string Name { get; set; }
}
}

//Car.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Car
{
List<Person> _passengers = new List<Person>();

public void AddPassenger(Person p)
{
_passengers.Add(p);
Console.WriteLine("{0} added!", p.Name);
}

public void Drive()
{
foreach (var passenger in _passengers)
Console.WriteLine("Driving {0} ...!", passenger.Name);
}
}
}

//Driver.cs
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Driver
{
private Car _myCar = new Car();

public void DriveToMarket(IList<Person> passengers)
{
foreach (var passenger in passengers)
_myCar.AddPassenger(passenger);

_myCar.Drive();
}
}
}

//Program.cs
using System.Collections.Generic;
using System;

namespace DependencyInjectionForDummies
{
class Program
{
static void Main(string[] args)
{
new Driver().DriveToMarket(
new List<Person>
{
new Person{ Name="Ali" },
new Person{ Name="Vahid" }
});

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

توضیحات:
کلاس شخص (Person) جهت تعریف مسافرین، اضافه شده؛ سپس کلاس خودرو (Car) که اشخاص را می‌توان به آن اضافه کرده و سپس به مقصد رساند، تعریف گردیده است. همچنین کلاس راننده (Driver) که بر اساس لیست مسافرین، آن‌ها را به خودروی خاص ذکر شده هدایت کرده و سپس آن‌ها را با کمک کلاس خودرو به مقصد می‌رساند؛ نیز تعریف شده است. در پایان هم یک کلاینت ساده جهت استفاده از این کلاس‌ها ذکر شده است.
همانطور که ملاحظه می‌کنید کلاس راننده به کلاس خودرو گره خورده است و این راننده همیشه تنها از یک نوع خودروی مشخص می‌تواند استفاده کند و اگر روزی قرار شد از یک ون کمک گرفته شود، این کلاس باید بازنویسی شود.

خوب! اکنون اگر این کلاس‌ها را بر اساس الگوی تزریق وابستگی‌ها (روش تزریق در سازنده که در قسمت قبل بحث شد) بازنویسی کنیم به کلاس‌های زیر خواهیم رسید:

//ICar.cs
using System;

namespace DependencyInjectionForDummies
{
interface ICar
{
void AddPassenger(Person p);
void Drive();
}
}

//Car.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Car : ICar
{
//همانند قسمت قبل
}
}

//Van.cs
using System;
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Van : ICar
{
List<Person> _passengers = new List<Person>();

public void AddPassenger(Person p)
{
_passengers.Add(p);
Console.WriteLine("{0} added!", p.Name);
}

public void Drive()
{
foreach (var passenger in _passengers)
Console.WriteLine("Driving {0} ...!", passenger.Name);
}
}
}

//Driver.cs
using System.Collections.Generic;

namespace DependencyInjectionForDummies
{
class Driver
{
private ICar _myCar;

public Driver(ICar myCar)
{
_myCar = myCar;
}

public void DriveToMarket(IList<Person> passengers)
{
foreach (var passenger in passengers)
_myCar.AddPassenger(passenger);

_myCar.Drive();
}
}
}

//Program.cs
using System.Collections.Generic;
using System;

namespace DependencyInjectionForDummies
{
class Program
{
static void Main(string[] args)
{
Driver driver = new Driver(new Van());
driver.DriveToMarket(
new List<Person>
{
new Person{ Name="Ali" },
new Person{ Name="Vahid" }
});

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

توضیحات:
در اینجا یک اینترفیس جدید به نام ICar اضافه شده است و بر اساس آن می‌توان خودروهای مختلفی را با نحوه‌ی بکارگیری یکسان اما با جزئیات پیاده سازی متفاوت تعریف کرد. برای مثال در ادامه، یک کلاس ون با پیاده سازی این اینترفیس تشکیل شده است. سپس کلاس راننده‌ی ما بر اساس ترزیق این اینترفیس در سازنده‌ی آن بازنویسی شده است. اکنون این کلاس دیگر نمی‌داند که دقیقا چه خودرویی را باید مورد استفاده قرار دهد و از وابستگی مستقیم به نوعی خاص از آن‌ها رها شده است؛ اما می‌داند که تمام خودروها، اینترفیس مشخص و یکسانی دارند. به تمام آن‌ها می‌توان مسافرانی را افزود و سپس به مقصد رساند. در پایان نیز یک راننده جدید بر اساس خودروی ون تعریف شده، سپس یک سری مسافر نیز تعریف گردیده و نهایتا متد DriveToMarket فراخوانی شده است.
به این صورت به یک سری کلاس اصطلاحا loosely coupled رسیده‌ایم. دیگر راننده‌ی ما وابسته‌ی به یک خودروی خاص نیست و هر زمانی که لازم بود می‌توان خودروی مورد استفاده‌ی او را تغییر داد بدون اینکه کلاس راننده را بازنویسی کنیم.
یکی دیگر از مزایای تزریق وابستگی‌ها ساده سازی unit testing کلاس‌های برنامه توسط mocking frameworks است. به این صورت توسط این نوع فریم‌ورک‌ها می‌توان رفتار یک خودرو را تقلید کرد بجای اینکه واقعا با تمام ریز جرئیات آن‌ها بخواهیم سروکار داشته باشیم (وابستگی‌ها را به صورت مستقل می‌توان آزمایش کرد).

مطالب
آشنایی با الگوی IOC یا Inversion of Control (واگذاری مسئولیت)

کلاس Kid را با تعریف زیر در نظر بگیرید. هدف از آن نگهداری اطلاعات فرزندان یک شخص خاص می‌باشد:

namespace IOCBeginnerGuide
{
class Kid
{
private int _age;
private string _name;

public Kid(int age, string name)
{
_age = age;
_name = name;
}

public override string ToString()
{
return "KID's Age: " + _age + ", Kid's Name: " + _name;
}
}
}

اکنون کلاس والد را با توجه به اینکه در حین ایجاد این شیء، فرزندان او نیز باید ایجاد شوند؛ در نظر بگیرید:
using System;

namespace IOCBeginnerGuide
{
class Parent
{
private int _age;
private string _name;
private Kid _obj;

public Parent(int personAge, string personName, int kidsAge, string kidsName)
{
_obj = new Kid(kidsAge, kidsName);
_age = personAge;
_name = personName;
}

public override string ToString()
{
Console.WriteLine(_obj);
return "ParentAge: " + _age + ", ParentName: " + _name;
}
}
}

و نهایتا مثالی از استفاده از آن توسط یک کلاینت:

using System;

namespace IOCBeginnerGuide
{
class Program
{
static void Main(string[] args)
{
Parent p = new Parent(35, "Dev", 6, "Len");
Console.WriteLine(p);

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

که خروجی برنامه در این حالت مساوی سطرهای زیر می‌باشد:

KID's Age: 6, Kid's Name: Len
ParentAge: 35, ParentName: Dev

مثال فوق نمونه‌ای از الگوی طراحی ترکیب یا composition می‌باشد که به آن Object Dependency یا Object Coupling نیز گفته می‌شود. در این حالت ایجاد شیء والد وابسته است به ایجاد شیء فرزند.

مشکلات این روش:
1- با توجه به وابستگی شدید والد به فرزند، اگر نمونه سازی از شیء فرزند در سازنده‌ی کلاس والد با موفقیت روبرو نشود، ایجاد نمونه‌ی والد با شکست مواجه خواهد شد.
2- با از بین رفتن شیء والد، فرزندان او نیز از بین خواهند رفت.
3- هر تغییری در کلاس فرزند، نیاز به تغییر در کلاس والد نیز دارد (اصطلاحا به آن Dangling Reference هم گفته می‌شود. این کلاس آویزان آن کلاس است!).

چگونه این مشکلات را برطرف کنیم؟
بهتر است کار وهله سازی از کلاس Kid به یک شیء، متد یا حتی فریم ورک دیگری واگذار شود. به این واگذاری مسئولیت، delegation و یا inversion of control - IOC نیز گفته می‌شود.

بنابراین IOC می‌گوید که:
1- کلاس اصلی (یا همان Parent) نباید به صورت مستقیم وابسته به کلاس‌های دیگر باشد.
2- رابطه‌ی بین کلاس‌ها باید بر مبنای تعریف کلاس‌های abstract باشد (و یا استفاده از interface ها).

تزریق وابستگی یا Dependency injection
برای پیاده سازی IOC از روش تزریق وابستگی یا dependency injection استفاده می‌شود که می‌تواند بر اساس constructor injection ، setter injection و یا interface-based injection باشد و به صورت خلاصه پیاده سازی یک شیء را از مرحله‌ی ساخت وهله‌ای از آن مجزا و ایزوله می‌سازد.

مزایای تزریق وابستگی‌ها:
1- گره خوردگی اشیاء را حذف می‌کند.
2- اشیاء و برنامه را انعطاف پذیرتر کرده و اعمال تغییرات به آن‌ها ساده‌تر می‌شود.

روش‌های متفاوت تزریق وابستگی به شرح زیر هستند:

تزریق سازنده یا constructor injection :
در این روش ارجاعی از شیء مورد استفاده، توسط سازنده‌ی کلاس استفاده کننده از آن دریافت می‌شود. برای نمونه در مثال فوق از آنجائیکه کلاس والد به کلاس فرزندان وابسته است، یک ارجاع از شیء Kid به سازنده‌ی کلاس Parent باید ارسال شود.
اکنون بر این اساس تعاریف، کلاس‌های ما به شکل زیر تغییر خواهند کرد:

//IBuisnessLogic.cs
namespace IOCBeginnerGuide
{
public interface IBuisnessLogic
{
}
}

//Kid.cs
namespace IOCBeginnerGuide
{
class Kid : IBuisnessLogic
{
private int _age;
private string _name;

public Kid(int age, string name)
{
_age = age;
_name = name;
}

public override string ToString()
{
return "KID's Age: " + _age + ", Kid's Name: " + _name;
}
}
}

//Parent.cs
using System;

namespace IOCBeginnerGuide
{
class Parent
{
private int _age;
private string _name;
private IBuisnessLogic _refKids;

public Parent(int personAge, string personName, IBuisnessLogic obj)
{
_age = personAge;
_name = personName;
_refKids = obj;
}

public override string ToString()
{
Console.WriteLine(_refKids);
return "ParentAge: " + _age + ", ParentName: " + _name;
}
}
}

//CIOC.cs
using System;

namespace IOCBeginnerGuide
{
class CIOC
{
Parent _p;

public void FactoryMethod()
{
IBuisnessLogic objKid = new Kid(12, "Ren");
_p = new Parent(42, "David", objKid);
}

public override string ToString()
{
Console.WriteLine(_p);
return "Displaying using Constructor Injection";
}
}
}

//Program.cs
using System;

namespace IOCBeginnerGuide
{
class Program
{
static void Main(string[] args)
{
CIOC obj = new CIOC();
obj.FactoryMethod();
Console.WriteLine(obj);

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

توضیحات:
ابتدا اینترفیس IBuisnessLogic ایجاد خواهد شد. تنها متدهای این اینترفیس در اختیار کلاس Parent قرار خواهند گرفت.
از آنجائیکه کلاس Kid توسط کلاس Parent استفاده خواهد شد، نیاز است تا این کلاس نیز اینترفیس IBuisnessLogic را پیاده سازی کند.
اکنون سازنده‌ی کلاس Parent بجای ارجاع مستقیم به شیء Kid ، از طریق اینترفیس IBuisnessLogic با آن ارتباط برقرار خواهد کرد.
در کلاس CIOC کار پیاده سازی واگذاری مسئولیت وهله سازی از اشیاء مورد نظر صورت گرفته است. این وهله سازی در متدی به نام Factory انجام خواهد شد.
و در نهایت کلاینت ما تنها با کلاس IOC سرکار دارد.

معایب این روش:
- در این حالت کلاس business logic، نمی‌تواند دارای سازنده‌ی پیش فرض باشد.
- هنگامیکه وهله‌ای از کلاس ایجاد شد دیگر نمی‌توان وابستگی‌ها را تغییر داد (چون از سازنده‌ی کلاس جهت ارسال مقادیر مورد نظر استفاده شده است).

تزریق تنظیم کننده یا Setter injection
این روش از خاصیت‌ها جهت تزریق وابستگی‌ها بجای تزریق آن‌ها به سازنده‌ی کلاس استفاده می‌کند. در این حالت کلاس Parent می‌تواند دارای سازنده‌ی پیش فرض نیز باشد.

مزایای این روش:
- از روش تزریق سازنده بسیار انعطاف پذیرتر است.
- در این حالت بدون ایجاد وهله‌ای می‌توان وابستگی اشیاء را تغییر داد (چون سر و کار آن با سازنده‌ی کلاس نیست).
- بدون نیاز به تغییری در سازنده‌ی یک کلاس می‌توان وابستگی اشیاء را تغییر داد.
- تنظیم کننده‌ها دارای نامی با معناتر و با مفهوم‌تر از سازنده‌ی یک کلاس می‌باشند.

نحوه‌ی پیاده سازی آن:
در اینجا مراحل ساخت Interface و همچنین کلاس Kid با روش قبل تفاوتی ندارند. همچنین کلاینت نهایی استفاده کننده از IOC نیز مانند روش قبل است. تنها کلاس‌های IOC و Parent باید اندکی تغییر کنند:

//Parent.cs
using System;

namespace IOCBeginnerGuide
{
class Parent
{
private int _age;
private string _name;

public Parent(int personAge, string personName)
{
_age = personAge;
_name = personName;
}

public IBuisnessLogic RefKID {set; get;}

public override string ToString()
{
Console.WriteLine(RefKID);
return "ParentAge: " + _age + ", ParentName: " + _name;
}
}
}

//CIOC.cs
using System;

namespace IOCBeginnerGuide
{
class CIOC
{
Parent _p;

public void FactoryMethod()
{
IBuisnessLogic objKid = new Kid(12, "Ren");
_p = new Parent(42, "David");
_p.RefKID = objKid;
}

public override string ToString()
{
Console.WriteLine(_p);
return "Displaying using Setter Injection";
}
}
}

همانطور که ملاحظه می‌کنید در این روش یک خاصیت جدید به نام RefKID به کلاس Parent اضافه شده است که از هر لحاظ نسبت به روش تزریق سازنده با مفهوم‌تر و خود توضیح دهنده‌تر است. سپس کلاس IOC جهت استفاده از این خاصیت اندکی تغییر کرده است.

ماخذ

مطالب
آشنایی با الگوی MVVM

حدود یک سال قبل الگوی MVVM زیاد معروف نبود (Model-View-ViewModel pattern). اما در 6 ماه اخیر، این الگو به یک متدولوژی جدی توسعه برنامه‌های WPF و سیلورلایت تبدیل شده. نمی‌شود به یک وبلاگ خوب WPF سر زد و خبری از این روش نباشد. حتی فریم ورک‌هایی هم برای آن طراحی شده که لیست آن‌ها را در این مقاله می‌توانید مشاهده نمائید.

مزایای این الگو چیست؟
  • جدا سازی Model و View
  • تولید کدهایی با قابلیت تست بالا
  • فایل‌های code-behind ایی با حداقل کد
و ...

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




ماخذ

مطالب
در هم تنیدگی کدهای خود را کمتر کنید

مطلب "آشنایی با الگوی MVP" مقدمه‌ی کوتاهی بود بر یکی از روش‌هایی که توسط آن می‌توان گره خوردگی کدهای خود را کمتر، نگهداری طولانی مدت و اعمال تغییرات بعدی به آن‌ها را ساده‌تر کرده و همچنین امکان استفاده مجدد از کدهای موجود را فراهم آورد. در همین ارتباط ویدیویی تحت عنوان Decoupling Your Code, By Example را می‌توانید از آدرس زیر دریافت کنید:



ماخذ



مطالب
کاهش پیچیدگی؛ قسمت اول: الگوی مورد خاص (Special Case Pattern)
مهمترین دستاورد  الگوی شیء نال ( Null Object Pattern ) این است که جریان کنترل (branch ) برای شاخه مثبت و منفی یکسان است و هیچگونه انشعاب شرطی بر اساس آزمون‌های null وجود ندارد. شی‌ءهای حقیقی دارای یک سری از رفتار‌ها هستند؛ ولی Null Object معمولا هیچ کاری را انجام نمی‌دهد. 

Null Object دارای هیچگونه اطلاعاتی نیست. اگر ما یک برنامه تجارت داشتیم که در آن درخواست خرید، Null Object را برگرداند، در واقع تمام سر نخ‌هایی را که چرا عملیات با شکست مواجه شد‌ه‌است، کنار می‌گذاریم. آیا این مبلغ در حساب کاربری کاربر کافی نیست و یا آیا آیتمی موجود نیست؟ 

در این مقاله حالت‌هایی را که الگوی طراحی Null Object، قادر به تشخیص آنها نیست را به وسیله الگوی طراحی Special case رفع می‌کنیم.


 الگوی طراحی Special Case 

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

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

چنین اشیائی به موارد خاص ( Special Case ) اشاره می‌کنند. ما می‌توانیم اشیاء مورد خاص ( Special Case ) را به عنوان نتایج واقعی عملیات بسازیم. فقط اگر تمام بررسی‌های کسب و کار به پایان برسند و عملیات موفقیت آمیز باشد، آنگاه شیء واقعی نتیجه را باز می‌گردانیم.


نمونه‌ای از پیاده سازی موارد خاص

این بخشی از رابط کاربری است که توسط سرویس‌های برنامه کاربردی اجرا می‌شود:

public interface IApplicationServices
{
    ...
    IReceiptViewModel LoggedInUserPurchase(string itemName);
}

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

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

       1)  سایت در دست تعمیر و نگهداری باشد.

       2)  کاربر ثبت نشده و یا فعال نیست.

       3) آیتمی موجود نیست و یا وجود ندارد.

       4)  موجودی کاربر کم باشد.

 برای هر یک از این موارد یک کلاس خاص را ایجاد می‌کنیم که رابط کاربری IReceiptViewModel را پیاده سازی خواهد کرد. 
public class DownForMaintenance: IReceiptViewModel
{
}
این ویو مدل نشان دهنده این می‌باشد که سایت در دست تعمیر و نگهداری است. در حال حاضر هیچ اطلاعات اضافی همراه آن نیست؛ اما بعدها می‌توانیم بعضی از ویژگی‌های آن را اضافه کنیم. برای مثال زمان برآورد که سایت چه زمانی دوباره باز می‌شود. 
public class InvalidUser: IReceiptViewModel
{
    public string UserName { get; private set; }

    public InvalidUser(string userName)
    {
        this.UserName = userName;
    }
}
این کلاس برای مواقعی که کاربر وجود نداشته باشد و یا غیر فعال باشد، مورد استفاده قرار می‌گیرد. اینبار شیء مورد خاص (Special case) دارای اطلاعات اضافی مانند نام کاربری که خرید آن شکست خورده است، می‌باشد. 
توجه داشته باشید موارد خاص InvalidUser زمانی تولید می‌شوند که حالت DownForMaintenance را با موفقیت گذرانده باشیم. این دقیقا همان لحظه‌ای است که برنامه ما می‌داند کاربر وارد سیستم شده‌است. 
این قاعده کلی در الگوی طراحی مورد خاص ( Special case ) است. همانطور که از طریق منطق دامنه ( Domain Logic ) پیشرفت می‌کنید، اطلاعات بیشتری جمع آوری می‌شود که هر کدام از آنها برای تولید یک مورد مورد خاص با ارزش‌تر، مورد استفاده قرار می‌گیرند.
public class OutOfStock: IReceiptViewModel
{
    public string UserName { get; private set; }
    public string ItemName { get; private set; }

    public OutOfStock(string userName, string itemName)
    {
        this.UserName = userName;
        this.ItemName = itemName;
    }
}
این ویو مدل نشان دهنده این است که آیتمی موجود نیست. اینبار ما نام کاربری و نام آیتم (معتبر) را می‌دانیم. این شیء شامل اطلاعاتی است که آیتم مشخص شده توسط کاربر ثبت شده موجود در انبار موجود نیست. 
public class InsufficientFunds: IReceiptViewModel
{
    public string UserName { get; private set; }
    public decimal Amount { get; private set; }
    public string ItemName { get; private set; }

    public InsufficientFunds(string userName, decimal amount, string itemName)
    {
        this.UserName = userName;
        this.Amount = amount;
        this.ItemName = itemName;
    }
}
در نهایت، این مدل اطلاعاتی را ارائه می‌دهد که کاربری خاص، موجودی کافی برای پرداخت اقلام درخواستی را ندارد. بازگشت یک مورد خاص ( Special case) بجای Null Object ساده که حاوی اطلاعات اضافی نیست، به ما اجازه می‌دهد که اطلاعات قابل تامل‌تری را به کاربر بازگشت دهیم.

مثال استفاده از موارد خاص ( Special case)
با این حال ما تعدادی از کلاس‌های مورد خاص را پیاده سازی کرده‌ایم که هر کدام برای سناریوهای منفی در برنامه است. در هر موردی که ما شیء null یا Null را استفاده می‌کردیم وآن را بازگشت می‌دادیم، اکنون دیگر فقط مورد خاص را ایجاد و باز می‌گردانیم.
public class ApplicationServices: IApplicationServices
{
    ...
    public IReceiptViewModel LoggedInUserPurchase(string itemName)
    {
        if (IsDownForMaintenance())
            return new DownForMaintenance();
        return this.domain.Purchase(Session.LoggedInUserName, itemName);
    }

    private bool IsDownForMaintenance()
    {
        return File.Exists("maintenance.lock");
    }
}
این پیاده سازی سرویس نرم افزاری است که می‌تواند برای موارد تعمیر و نگهداری در مواردی که برنامه در دست نیست، بازگرداننده شود. در غیر این صورت سرویس برنامه، سرویس  دامین را فراخوانی کرده و شیءای را که آنجا تولید می‌شود، بازگشت می‌دهد. 
در داخل سرویس دامنه، مسائل ممکن است بسیار پیچیده‌تر باشند که در اینجا پیاده سازی شده است:
public class DomainServices: IDomainServices
{
    public IReceiptViewModel Purchase(string userName, string itemName)
    {
        User user = this.userRepository.Find(userName);
        if (user == null)
            return new InvalidUser(userName);

        Account account = this.accountRepository.FindByUser(user);
        return this.Purchase(user, account, itemName);
    }

    private IReceiptViewModel Purchase(User user, Account account, string itemName)
    {
        Product item = this.productRepository.Find(itemName);
        if (item == null)
            return new OutOfStock(user.UserName, itemName);

        ReceiptDto receipt = user.Purchase(item);
        MoneyTransaction transaction = account.Withdraw(receipt.Price);
        if (transaction == null)
            return new InsufficientFunds(user.UserName, receipt.Price, itemName);

        return receipt;
    }
}
در این مورد، اگر در سرویس‌های دامنه، چیزی اشتباه برآورده شود، موارد خاصی را باز می‌گردانند. فقط در پایان اجرا، اگر همه چیز خوب پیش رود، سرویس دامنه یک شیء واقعی را بازگشت خواهد داد.
به این ترتیب زمانیکه کاربر درخواست خریدی را می‌کند، خدمات برنامه و دامنه، اطلاعات و اتفاقات لازم را به لایه نمایش ارسال می‌کنند. اگر خرید با خطا رو به رو شد، لایه نمایش یک شیء را که حاوی تمام داده‌های موجود در مورد دلایل شکست است، دریافت می‌کند. اگر خرید با موفقیت باشد، لایه نمایش یک شیء را دریافت خواهد کرد که قادر به نمایش آن به کاربر خواهد بود.

نتیجه گیری
الگوی طراحی مورد خاص، مکمل ایده الگوی Null Object است. در بسیاری از موارد، Null Object واقعا قابل اجرا نیست؛ زیرا اطلاعاتی را درباره آنکه چرا هیچ خاصیت خاصی تولید نمی‌شود، ارائه نمی‌دهد. special case شیء خاصی است که اطلاعات بیشتری را ارائه می‌دهد.
نتیجه این پیچیدگی در کد این است که تماس گیرنده مجبور به انجام if-then-else بر اساس اینکه آیا شیء null یا غیر null است، دیگر نیست. رفرنس‌ها همیشه غیر Null خواهند بود. تنها تفاوت قابل ملاحظه‌ای که بین الگوهای Null Object و Special case وجود دارد این است که الگوی خاص ( Special Case) رفتارهای پیچیده‌تری را از خود نشان می‌دهد. از این رو، الگوی مورد خاص را می‌توان به سناریوهای پیچیده‌تری اعمال کرد که تماس گیرنده را از منطق if-then-else محافظت می‌کند. 
مطالب
پیاده سازی Option یا Maybe در #C

Options یا Maybe در یک زبان تابعی مثل #F، نشان دهنده‌ی این است که شیء (Object) ممکن است وجود نداشته باشد(Null Reference) که یکی از مهمترین ویژگی‌های یک زبان شیءگرا مثل #C و یا Java محسوب می‌شودما برنامه نویس‌ها (اغلب) از هرچیزی که باعث کرش برنامه می‌شود، بیزاریم و برای اینکه برنامه کرش نکند، مجبور میشویم تمام کد‌های خود  را از Null Reference محافظت کنیم. تمام این مشکلات توسط Tony Hoare مخترع ALOGL است که تنها دلیل وجود Null References را سادگی پیاده سازی آن می‌داند و او این مورد را یک «خطای  میلیون دلاری» نامیده‌است. 

به این مثال توجه بفرمایید: 

public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

public class UserService : IUserService
    {
        private IList<User> _userData;

        public UserService()
        {
            _userData = new List<User>
            {
                new User {Id = 1,Name = "ali"},
                new User {Id = 2,Name = "Karim"}
            };
        }

        public User GetById(int id)
        {
            return _userData.FirstOrDefault(x => x.Id == id);
        }
    }  

public class UserController : Controller
    {
        private readonly IUserService _userService;

        public UserController(IUserService  userService)
        {
            _userService = userService;
        }
        public ActionResult Details(int id)
        {
            var user=_userService.GetById(3); // این متد ممکن است مقداری برگرداند و یا مقدار نال برگرداند                           
            if( user == null)
                 return HttpNotFound();    
            return View(user);  
        }
    }

این کدی است که ما برنامه نویسان به صورت متداولی با آن سروکار داریم. اما چه چیزی درباره این کد اشکال دارد؟

مشکل از آن جایی هست که ما نمی‌دانیم متد GetById مقداری را برمیگرداند و یا Null را بر می‌گرداند. این متد هرگاه که امکان برگرداندن Null وجود داشته باشد، خطای  NullReferenceException را در زمان اجرا بر می‌گرداند و همان طور که میدانید، به ازای هر شرطی که به برنامه اضافه میکنیم، پیچیدگی برنامه هم افزایش می‌یابد و کد خوانایی خود را از دست می‌دهد. تصور کنید دنیایی بدون NullReferenceException چه دنیایی زیبایی می‌بود؛ ولی متاسفانه این مورد از ویژگی‌های زبان #C است. خوشبختانه راه‌حل‌های برای حل NRE ارائه شده‌اند که در ادامه به آن‌ها می‌پردازیم.

ما می‌خواهیم متد GetById همیشه چیزی غیر از نال را برگرداند و یکی از راه‌هایی که ما را به این هدف می‌رساند این است که این متد یک توالی را برگرداند.

به نگاری جدید کد توجه بفرمایید:
public class UserService : IUserService
    {
        private IList<User> _userData;

        public UserService()
        {
            _userData = new List<User>
            {
                new User {Id = 1,Name = "ali"},
                new User {Id = 2,Name = "Karim"}
            };
        }

        public IEnumerable<User> GetById(int id)
        {
            var user = _userData.FirstOrDefault(x => x.Id == id);
            if (user == null) return new User[0];
            return new[] { user };
        }
    } 

اگر به امضای متد GetById توجه کنید، به جای اینکه User را برگرداند، این متد یک توالی از User را بر می‌گرداند و اگر در اینجا کاربری یافت شد، این توالی دارای یک المان خواهد بود و در غیر این صورت اگر User یافت نشد، این متد یک توالی را بر می‌گرداند که دارای هیچ المانی نیست. در ادامه اگر کلاینت بخواهد از متد GetById استفاده کند، به صورت زیر خواهد بود:

 public ActionResult Details(int id)
        {
            var user = _userService
                            .GetById(3)
                            .DefaultIfEmpty(new User())
                            .Single();
            return View(user);
        }

 متد GetById دارای دو وجه است و وجه مثبت آن این است که اگر مجموعه دارای مقداری باشد، هیچ مشکلی نیست؛ ولی اگر مجموعه دارای المانی نباشد، باید یک شیء را به صورت پیش فرض به آن اختصاص دهیم که این کار را با استفاده از متد DefualtIfEmpty انجام داده‌ایم. 

 در اول مقاله هم اشاره کردیم که  Maybe یا Options، مجموعه‌ای است که دارای یک المان و یا هیچ المانی است. اگر به امضای متد GetById توجه کنید، متوجه خواهید شد که این متد می‌تواند مجموعه‌ای را برگرداند و نمی‌تواند گارانتی کند که حتما مجموعه‌ای را بر می‌گرداند که دارای یک المان و یا هیچ باشد. برای حل این مشکل می‌توانیم از کلاس Option استفاده کنیم:

public class Option<T> : IEnumerable<T>
    {
        private readonly T[] _data;

        private Option(T[] data)
        {
            _data = data;
        }

        public static Option<T> Create(T element) => new Option<T>(new[] { element });

        public static Option<T> CreateEmpty() => new Option<T>(new T[0]);

        public IEnumerator<T> GetEnumerator() => ((IEnumerable<T>) _data).GetEnumerator();

        IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
    }

تنها دلیل استفاده از متد‌های Create و CreateEmpty این است که به خوانایی برنامه کمک کنیم؛ نه بیشتر. در ادامه اگر بخواهیم از کلاس option استفاده کنیم، به صورت زیر خواهد بود:

 public class UserService : IUserService
    {
       ...
       ...
       public Option<User> GetById(int id)
        {
            var user = _userData.FirstOrDefault(x => x.Id == id);
            return user == null ? Option<User>.CreateEmpty() : Option<User>.Create(user);
        }
    }

 public class UserController : Controller
    {
       ...
       ...
       public ActionResult Details(int id)
        {
            var user = _userService
                            .GetById(3)
                            .DefaultIfEmpty(new User())
                            .Single();
            return View(user);
        }
    }


چکیده:

مدیریت کردن References کار بسیار پیچیده‌ای است. قبل از آن که تلاش کنیم مقداری را برگردانیم و یا عملیاتی را بر روی آن انجام دهیم، اول باید مطمئن شویم که این شیء به جایی اشاره می‌کند. نمونه‌های متفاوتی از Option و یا Maybe را می‌توانید در اینترنت پیدا کنید که هدف نهایی آن‌ها، حذف NullReferenceException است و آشنایی با این ایده، شما را به دنیای برنامه نویسی تابعی در#C هدایت می‌کند.

مطالب
بررسی چند نکته در مورد ارث بری کلاس‌ها در #C
مقدمه
وراثت، بین کلاس‌های والد (Parent) و فرزند (Child) ارتباط ایجاد می‌کند. در این مطلب، با یک مثال ساده، نکات مختلفی را بررسی خواهیم کرد.

در ابتدا کلاس‌هایی را با نام parent و child، به شکل زیر ایجاد می‌کنیم:
public class Parent
{
  public Parent()
  {
            Console.WriteLine("Parent Constructor");
  }
  public void Print()
  {
            Console.WriteLine("Parent Print");
  }
} public class Child : Parent { public Child() { Console.WriteLine("Child Constructor"); } public void Print() { Console.WriteLine("Child Print"); } }
با کامپایل کد فوق، هشدار (نه خطا) زیر توسط ویژوال استودیو صادر خواهد شد:

هشدارفوق این نکته را تذکر می‌دهد که متد Print تعریف شده در کلاس Child، پیاده سازی متد Print را در کلاس والد، مخفی (Hide) می‌کند. به همین خاطر پیشنهاد می‌کند که اگر واقعا قصد چنین کاری را داریم (نادیده گرفتن پیاده سازی print کلاس والد) از کلمه کلیدی (keyword) new استفاده کنیم. بدین شکل:
 public new void Print()
  {
     Console.WriteLine("Child Print");
  }
حال با نمونه سازی کلاس‌های فوق، رفتار سازنده و متد Print را بررسی می‌کنیم:
Console.WriteLine("====Parent====");
Parent parent = new Parent();
parent.Print();

Console.WriteLine("====Child====");
Child child = new Child();
child.Print();

Console.WriteLine("====Parent Via Child====");
Parent pc = new Child();
pc.Print();
در قسمت اول نمونه سازی از والد، نکته خاصی وجود ندارد. در ابتدا سازنده و سپس فراخوانی متد Print اتفاق خواهد افتاد.
در قسمت دوم نمونه سازی از فرزند، ابتدا سازنده والد و سپس سازنده فرزند فراخوانی خواهند.
در بخش سوم، یک نمونه فرزند را از نوع والد، ایجاد کرد‌هایم .( () Parent pc=new Child). در این بخش ابتدا سازنده والد و بعد از آن سازنده فرزند، فراخوانی می‌شود و با فراخوانی متد Print، متد والد اجرا خواهد شد.


استفاده از Virtual  و Override
اگر بدنبال این باشیم که در قسمت سوم متد Print فرزند فراخوانی شود، مفاهیم virtual و override به کمک ما خواهند آمد:
  public class Parent
{
  public Parent()
  {
Console.WriteLine("Parent Constructor");
  }

  public virtual void  Print()
  {
Console.WriteLine("Parent Print");
  }
}

public class Child : Parent
{
  public Child()
  {
Console.WriteLine("Child Constructor");
  }

  public override void Print()
  {
Console.WriteLine("Child Print");
  }
}
با تعریف متد از نوع virtual، امکان تحریف رفتار پیش فرض متد را توسط فرزند‌ها، مهیا خواهیم کرد. فرزندان نیز با override کردن متد والد، پیاده سازی خود را اعمال می‌کنند.
اگر خروجی کد بالا را با قسمت قبل مقایسه کنید، متوجه خواهید شد که در قسمت سوم فرزند، رفتار متد والد را تحریف/بازنویسی (override) کرده است ( پیاده سازی فرزند اجرا شده است).


سازنده‌های استاتیک (Static Constructor)
سازنده‌های استاتیک برای مقدار دهی به داده‌های استاتیک و یا انجام عملیاتی که تنها قرار است یکبار انجام شوند مورد استفاده قرار میگیرند. این سازنده‌ها بصورت اتوماتیک قبل از ساخت نمونه و مقداردهی اعضای استاتیک و قبل از سازنده‌های غیر استاتیک اجرا می‌شوند.
   public class Parent
{
  static Parent()
  {
Console.WriteLine("Parent static Constructor");
  }
  public Parent()
  {
Console.WriteLine("Parent Constructor");
  }

  public virtual void  Print()
  {
Console.WriteLine("Parent Print");
  }
}

public class Child : Parent
{
  static Child()
  {
Console.WriteLine("Child static Constructor");
  }
  public Child()
  {
Console.WriteLine("Child Constructor");
  }

  public override void Print()
  {
Console.WriteLine("Child Print");
  }
در بخش سوم در ابتدا سازنده استاتیک فرزند و سپس سازنده استاتیک والد فراخوانی خواهند شد و ترتیب اجرای سایر متد‌ها و سازنده‌ها مثل قبل است.




  جمع بندی
* اگر نمونه‌ای از یک فرزند را ایجاد کنیم، ابتدا سازنده‌ی والد فراخوانی خواهد شد و پس از آن سازنده‌ی کلاس فرزند.
* اگر قصد تحریف رفتار متد والد را در فرزندان داریم، می‌توانیم این متد‌ها را در کلاس والد بصورت virtual تعریف کنیم.
نظرات اشتراک‌ها
چرا EF انتخاب خوبی برای پروژه های Domain-Driven نیست؟

زمانیکه متدهای Add و Remove به داخل entityها منتقل می‌شن، الگویی حاصل میشه به نام Active record. این الگو در اصل یک ضد الگو هست به این دلایل:

- متدهای CRUD به اینترفیس عمومی موجودیت‌ها منتقل شدن.

- تست پذیری این نوع اشیاء پایین هست.

- SRP را نقض می‌کنند.

اطلاعات بیشتر

نظرات مطالب
EF Code First #12
هیچکدام. قسمت 11 را ابتدا مطالعه کنید (در مورد اینکه چرا نیازی به استفاده از الگوی مخزن با EF نیست).
سپس در سایت به مطالب تکمیلی زیر مراجعه کنید: 
 به الگوی Repository در لایه DAL خود نه بگویید!
پیاده سازی generic repository یک ضد الگو است 
ایجاد Repositories بر روی UnitOfWork 
نگاهی به generic repositories
بدون معکوس سازی وابستگی‌ها، طراحی چند لایه شما ایراد دارد   
نظرات مطالب
پیاده سازی پروژه نقاشی (Paint) به صورت شی گرا 5#
@کاوه احمدی
من خیلی سعی کردم طبق الگوی «کمپین ضد IF !»  عمل کردم، و پیش رفتم درست شد، اما به دلیل اینکه در زمان رسم شی در برنامه کاربری (اینترفیس) در زمان MouseMove پیش نمایش شی رسم می‌شود و در زمان MouseUp خود شی رسم می‌شود این امکان نداشتم تا از شی نمونه سازی کنم و طبق اون الگو پیش برم ، لطفا در صورتی که روشم اشتباست اصلاح بفرمایین.
موفق وموید باشید.