مطالب
الگوی وضعیت State Pattern
الگوی وضعیت، یکی از الگوهای رفتاری Gang Of Four است و بسیار شبیه به الگوی Strategy  می‌باشد؛ ولی با کپسوله سازی بیشتر. در الگوی استراتژی تغییر وضعیت از بیرون کلاس اعمال می‌د ولی در الگوی وضعیت، بر اساس تغییر وضعیت درونی خودش صورت می‌گیرد.
یکی از استفاده‌های این الگو برای مثال در پلیرهاست که وضعیت پخش را چون Play,Pause و ... در خود دارند. در اینجا هم از این مثال استفاده می‌کنیم:
ابتدا یک اینترفیس برای وضعیت خود بسازید که آرگومان ورودی متد آن را در مرحله بعد تعریف میکنیم:
public interface IState
{
    void PressPlay(MP3PlayerContext context);
}
سپس نوبت ایجاد کلاس اصلی یا همان دستگاه پخش که به آن Context می‌گوییم می‌رسد تا تغییر وضعیت الگو را به آن بسپاریم:
public class MP3PlayerContext
{
    public MP3PlayerContext()
    {
        this.CurrentState = new StandbyState();
    }
    
    public MP3PlayerContext(IState state)
    {
       this.CurrentState = state; 
    }
    
    public IState CurrentState { get; set; }
    
    public void Play()
    {
        this.CurrentState.PressPlay(this);
    }
}
سپس کلاس‌های مختلف خود را بر اساس اینترفیس بالا می‌سازیم:
public class StandbyState : IState
{
    public void PressPlay(MP3PlayerContext context)
    {
        context.CurrentState = new PlayingState();
    }
}

public class PlayingState : IState
{
    public void PressPlay(MP3PlayerContext context)
    {
        context.CurrentState = new StandbyState();
    }
}
در کدهای بالا، کلاس‌های Playing و StandBy در واقع شبیه سازی از عمل کلید پخش هستند که با هر بار فشردن آن، پخش به طور موقت توقف کرده و یا پخش خود را از سر می‌گیرد. کلاس Context نیز باید در ابتدا به طور پیش فرض با یکی از این مقادیر پر شود و برای دکمه پخش مشخص است که کلاس PlayingState می‌باشد.
بدین ترتیب در اولین اجرای متد Play در کلاس Context، کلاس PlayingState اجرا می‌شود و وضعیت، به StandbyState تغییر می‌کند و هر بار که مجددا متد Play اجرا گردد، تعویض بین این دو کلاس صورت می‌گیرد.
مطالب
معرفی Decorator Design Pattern

فرض کنید که می‌خواهیم یک برنامه برای یک فروشگاه نوشیدنی (مانند coffee shop) بنویسیم ، این فروشگاه در ابتدای کار ممکن است ، منوی ساده‌ای جهت ارائه به مشتری داشته باشد. برای مثال ممکن است که فقط 3 یا 4 محصول داشته باشد. بنابراین ممکن است ما برنامه‌ای را که می‌خواهیم برای این مشتری بنویسیم به صورت زیر طراحی کنیم:

 


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

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

 

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

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

خوب ما به این مسئله به این صورت نگاه می‌کنیم که شروع می‌کنیم با نوشیدنی‌ها و آن‌ها را با چاشنی‌ها در زمان اجرا تزیین (Decorate) می‌کنیم؛ نه کامپایل.

برای مثال اگر مشتری ما یک نوشیدنی DarkRoast با Mocha و Whip خواست، سپس ما :
1- یک شی از DarkRoast  ایجاد می‌کنیم .
2- آن را با یک شی از  Mocha  تزئین می‌کنیم.
3- آن را با یک شی از Whip - تزیین می‌کنیم.
4- متد Cost()  را صدا می‌زنیم و  یک Delegation  را برای اضافه کردن قیمت چاشنی‌ها در نظر می‌گیریم.

بسیار خوب؛ اما ما عملیات تزئین یک شی را چگونه انجام می‌دهیم و delegation ما چگونه عمل می‌کند .
یک اشاره : به شیء تزئین کننده، مانند یک Wrappers فکر کنید. اجاز بدهید ببینم که چه طور این کار را انجام می‌دهیم.
1- یک شی از DarkRoast  ایجاد می‌کنیم.
 
 

2- آن را با یک شی از  Mocha  تزئین می‌کنیم.

3- آن را با یک شی از Whip تزیین می‌کنیم 


 4- حالا زمان محاسبه قیمت محصول برای مشتری فرا رسیده است. ما این کار را را با صدا زدن بیرونی‌ترین Decorator(Whip)  انجام می‌دهیم و شی  whip به کمک  Delegate مابقی توابع cost را صدا می‌زند.



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

public abstract class Beverage
{
     string description ="unknow beverage";
     public String getDescription(){
         return description;
     }
     public abstract double cost();
}

public abstract class CondimentDecorator extends Beverage {
    public abstract string getDescription();
}

public class Espersso extends Beverage{
   public Espersso()
   {
      description="Espersso";
   }
   public double cost(){
     return 1.99;
   }
}

public class HouseBelend extends Beverage {
   public HouseBelend()
   {
     description="HouseBelend";
   }
   public double cost()
   {
     return .89;
   }
}

public class mocha extends condimateDecorator {
  Beverage beverage;
  public mocha(Beverage beverage)
  {
     this.beverage=beverage;
  }
   public string getDescription(){
      return beverage.getdescription() + "Mocha";
   }
   public double cost(){
     return .20 +beverage.cost
   }
}


// Now Use These classes in Final form
Beverage beverage=new Espersso();
//Customers want a coffe with double milk and whip
beverage=new mocha(beverage);
beverage=new mocha(meverage);
beverage=new whip(beverage);

system.out.println(beverage.getDescription() + "$" +beverage.cost());
مطالب
ویدیوهای آموزشی MVVM

یک سری ویدیوی رایگان آموزشی MVVM از مایکروسافت و همچنین شرکت Infragistics در دسترس هستند که جهت سهولت، لیست آن‌ها را ادامه می‌توانید مشاهده نمائید:


مطالب
تزریق وابستگی (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 است. به این صورت توسط این نوع فریم‌ورک‌ها می‌توان رفتار یک خودرو را تقلید کرد بجای اینکه واقعا با تمام ریز جرئیات آن‌ها بخواهیم سروکار داشته باشیم (وابستگی‌ها را به صورت مستقل می‌توان آزمایش کرد).

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

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

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

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




ماخذ

مطالب
Dependency Injection

در ادامه مباحث بهتر کد بنویسیم و الگوهایی که در این رابطه معرفی شدند، اخیرا کتابی از انتشارات manning منتشر شده تحت عنوان Dependency Injection . هر چند به ظاهر این کتاب برای جاوا کارها تهیه شده اما قسمت عمده‌ای از آن برای سایر زبان‌های برنامه نویسی دیگر نیز قابل استفاده است.




DESCRIPTION
In object-oriented programming, a central program normally controls other objects in a module, library, or framework. With dependency injection, this pattern is inverted—a reference to a service is placed directly into the object which eases testing and modularity. Spring or Google Guice use dependency injection so you can focus on your core application and let the framework handle infrastructural concerns.
Dependency Injection explores the DI idiom in fine detail, with numerous practical examples that show you the payoffs. You'll apply key techniques in Spring and Guice and learn important pitfalls, corner-cases, and design patterns. Readers need a working knowledge of Java but no prior experience with DI is assumed.

WHAT'S INSIDE:
◊ How to apply it (Understand it first!)
◊ Design patterns and nuances
◊ Spring, Google Guice, PicoContainer, and more
◊ How to integrate DI with Java frameworks


راستی، این کتاب تر و تازه رو می‌تونید از همین کتاب فروشی‌های دور و اطراف نیز تهیه کنید! در سایت booktraining دات ارگ در قسمت graphics-and-design به تاریخ 4 آگوست.



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

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



ماخذ



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

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

یکی از الگوهایی که شیوه‌ی صحیح این جدا سازی را ترویج می‌کند، الگوی MVP یا Model-View-Presenter می‌باشد. خلاصه‌ی این الگو به صورت زیر است:


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

View :
من می‌دانم که چگونه باید اطلاعاتی را به کاربر به شکلی بصری ارائه داد.
من می‌دانم که چگونه باید اعمالی مانند data binding و امثال آن را انجام داد.
من نمی‌دانم که چگونه باید منطق پردازشی موارد ذکر شده را فراهم آورم.

Presenter :
من می‌دانم که چگونه باید درخواست‌های رسیده کاربر به View را دریافت کرده و آن‌ها را به Model‌ انتقال دهم.
من می‌دانم که چگونه باید اطلاعات را به Model ارسال کرده و سپس نتیجه‌ی پردازش آن‌ها را جهت نمایش در اختیار View قرار دهم.
من نمی‌دانم که چگونه باید اطلاعاتی را ترسیم کرد (مشکل View است نه من) و نمی‌دانم که چگونه باید پردازشی را بر روی اطلاعات انجام دهم. (مشکل Model است و اصلا ربطی به اینجانب ندارد!)


یک مثال ساده از پیاده سازی این روش
برنامه‌ای وبی را بنویسید که پس از دریافت شعاع یک دایره از کاربر، مساحت ‌آن‌را محاسبه کرده و نمایش دهد.
یک تکست باکس در صفحه قرار خواهیم داد (txtRadius) و یک دکمه جهت دریافت درخواست کاربر برای نمایش نتیجه حاصل در یک برچسب به نام lblResult

الف) پیاده سازی به روش متداول (اسپاگتی کد)

protected void btnGetData_Click(object sender, EventArgs e)
{
lblResult.Text = (Math.PI * double.Parse(txtRadius.Text) * double.Parse(txtRadius.Text)).ToString();
}
بله! کار می‌کنه!
اما این مشکلات را هم دارد:
- منطق برنامه (روش محاسبه مساحت دایره) با رابط کاربر گره خورده.
- کدهای برنامه در پروژه‌ی دیگری قابل استفاده نیست. (شما متد یا کلاسی را این‌جا با قابلیت استفاده مجدد می‌توانید پیدا می‌کنید؟ آیا یکی از اهداف برنامه نویسی شیءگرا تولید کدهایی با قابلیت استفاده مجدد نبود؟)
- چگونه باید برای آن آزمون واحد نوشت؟

ب) بهبود کد و جدا سازی لایه‌ها از یکدیگر

در روش MVP متداول است که به ازای هر یک از اجزاء ابتدا یک interface نوشته شود و سپس این اینترفیس‌ها پیاده سازی گردد.

پیاده سازی منطق برنامه:

1- ایجاد Model :
یک فایل جدید را به نام CModel.cs به پروژه اضافه کرده و کد زیر را به آن خواهیم افزود:

using System;

namespace MVPTest
{
public interface ICircleModel
{
double GetArea(double radius);
}

public class CModel : ICircleModel
{
public double GetArea(double radius)
{
return Math.PI * radius * radius;
}
}
}
همانطور که ملاحظه می‌کنید اکنون منطق برنامه از موارد زیر اطلاعی ندارد:
- خبری از textbox و برچسب و غیره نیست. اصلا نمی‌داند که رابط کاربری وجود دارد یا نه.
- خبری از رخ‌دادهای برنامه و پاسخ دادن به آن‌ها نیست.
- از این کد می‌توان مستقیما و بدون هیچ تغییری در برنامه‌های دیگر هم استفاده کرد.
- اگر باگی در این قسمت وجود دارد، تنها این کلاس است که باید تغییر کند و بلافاصله کل برنامه از این بهبود حاصل شده می‌تواند بدون هیچگونه تغییری و یا به هم ریختگی استفاده کند.
- نوشتن آزمون واحد برای این کلاس که هیچگونه وابستگی به UI ندارد ساده است.


2- ایجاد View :
فایل دیگری را به نام CView.cs را به همراه اینترفیس زیر به پروژه اضافه می‌کنیم:

namespace MVPTest
{
public interface IView
{
string RadiusText { get; set; }
string ResultText { get; set; }
}
}

کار View دریافت ابتدایی مقادیر از کاربر توسط RadiusText و نمایش نهایی نتیجه توسط ResultText است البته با یک اما.
View نمی‌داند که چگونه باید این پردازش صورت گیرد. حتی نمی‌داند که چگونه باید این مقادیر را به Model جهت پردازش برساند یا چگونه آن‌ها را دریافت کند (به همین جهت از اینترفیس برای تعریف آن استفاده شده).

3- ایجاد Presenter :
در ادامه فایل جدیدی را به نام CPresenter.cs‌ با محتویات زیر به پروژه خواهیم افزود:

namespace MVPTest
{
public class CPresenter
{
IView _view;

public CPresenter(IView view)
{
_view = view;
}

public void CalculateCircleArea()
{
CModel model = new CModel();
_view.ResultText = model.GetArea(double.Parse(_view.RadiusText)).ToString();
}
}
}

کار این کلاس برقراری ارتباط با Model است.
می‌داند که چگونه اطلاعات را به Model ارسال کند (از طریق _view.RadiusText) و می‌داند که چگونه نتیجه‌ی پردازش را در اختیار View قرار دهد. (با انتساب آن به _view.ResultText)
نمی‌داند که چگونه باید این پردازش صورت گیرد (کار مدل است نه او). نمی‌داند که نتیجه‌ی نهایی را چگونه نمایش دهد (کار View است نه او).
روش معرفی View به این کلاس به constructor dependency injection معروف است.

اکنون کد وب فرم ما که در قسمت (الف) معرفی شده به صورت زیر تغییر می‌کند:

using System;

namespace MVPTest
{
public partial class _Default : System.Web.UI.Page, IView
{
protected void Page_Load(object sender, EventArgs e)
{
}

public string RadiusText
{
get { return txtRadius.Text; }
set { txtRadius.Text = value; }
}
public string ResultText
{
get { return lblResult.Text; }
set { lblResult.Text = value; }
}

protected void btnGetData_Click(object sender, EventArgs e)
{
CPresenter presenter = new CPresenter(this);
presenter.CalculateCircleArea();
}
}
}

در این‌جا یک وهله از Presenter برای برقراری ارتباط با Model ایجاد می‌شود. همچنین کلاس وب فرم ما اینترفیس View را نیز پیاده سازی خواهد کرد.

مطالب
تفاوت ViewData و ViewBag و TempData و Session در MVC
در MVC راه‌های متفاوتی برای ارسال اطلاعات از controller به view و در redirect‌ها وجود دارد. در این مقاله سعی شده تفاوت‌های آنها به صورت مختصر نمایش داده شود. این مقاله در حقیقت یک ترجمه آزاد از این  مقاله  است که امیدوارم خوب ترجمه شده باشد.
ViewData:
  • ViewData یک نوع دیکشنری ویژه است که از ViewDataDictionary ارث بری کرده است.
  • برای ارسال اطلاعات از controller به view استفاده می‌شود.
  • مدت زمان اعتبار مقادیر آن تنها در request جاری است.
  • اگر redirect بین صفحات رخ دهد، مقدار آن null خواهد شد.
  • به دلایل امنیتی باید قبل از استفاده، null بودن آن تست شود.
  • برای بهره برداری باید cast صورت پذیرد.

ViewBag:
  • یک نوع dynamic است (این نوع در c# 4 معرفی شده است).
  • مانند ViewData برای ارسال اطلاعات از کنترلر به view استفاده می‌شود.
  • مدت زمان اعتبار مقادیر آن تنها در request جاری است.
  • اگر redirect بین صفحات رخ دهد، مقدار آن null خواهد شد.
  • به دلایل امنیتی باید قبل از استفاده، null بودن آن تست شود.
  • برای بهره برداری، cast نیاز نیست. بنابراین سریعتر عمل می‌کند.

TempData:
  • نوع خاصی از دیکشنری است که از TempDataDictionary مشتق شده است.
  • مدت عمر کوتاهی دارد و برای ارسال اطلاعات بین صفحات (در redirect) قابل استفاده است.
  • وقتی view‌ها به صورت کامل اجرا شود، مقادیر آن null می‌شود.
  • به دلایل امنیتی باید قبل از استفاده، null بودن آن تست شود.
  • برای بهره برداری باید cast صورت پذیرد.

Session:
  • برای ارسال اطلاعات بین request‌های مختلف مورد بهره برداری قرار می‌گیرد.
  • مقادیر آن null نمی‌شود. تنها پس از گذشت زمان مشخصی (session expire) مقادیر آن null می‌شود.
  • به دلایل امنیتی باید قبل از استفاده null بودن آن تست شود.
  • برای بهره برداری، باید cast صورت پذیرد.  
مطالب
نحوه ارتقاء برنامه‌های موجود MVC3 به MVC4
در ادامه، مراحل ارتقاء پروژه‌های قدیمی MVC3 را به ساختار جدید پروژه‌های MVC4 مرور خواهیم کرد.

1) نصب پیشنیاز
الف) نصب VS 2012
و یا
ب) نصب بسته MVC4 مخصوص VS 2010 (این مورد جهت سرورهای وب نیز توصیه می‌شود)

پس از نصب باید به این نکته دقت داشت که پوشه‌های زیر حاوی اسمبلی‌های جدید MVC4 هستند و نیازی نیست الزاما این موارد را از NuGet دریافت و نصب کرد:
C:\Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v2.0\Assemblies
C:\Program Files\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies
پس از نصب پیشنیازها
2) نیاز است نوع پروژه ارتقاء یابد
به پوشه پروژه MVC3 خود مراجعه کرده و تمام فایل‌های csproj و web.config موجود را با یک ادیتور متنی باز کنید (از خود ویژوال استودیو استفاده نکنید، زیرا نیاز است محتوای فایل‌های پروژه نیز دستی ویرایش شوند).
در فایل‌های csproj (یا همان فایل پروژه؛ که vbproj هم می‌تواند باشد) عبارت
{E53F8FEA-EAE0-44A6-8774-FFD645390401}
را جستجو کرده و با
{E3E379DF-F4C6-4180-9B81-6769533ABE47}
جایگزین کنید. به این ترتیب نوع پروژه به MVC4 تبدیل می‌شود.

3) به روز رسانی شماره نگارش‌های قدیمی
سپس تعاریف اسمبلی‌های قدیمی نگارش سه MVC و نگارش یک Razor را یافته (در تمام فایل‌ها، چه فایل‌های پروژه و چه تنظیمات):
System.Web.Mvc, Version=3.0.0.0
System.Web.WebPages, Version=1.0.0.0
System.Web.Helpers, Version=1.0.0.0
System.Web.WebPages.Razor, Version=1.0.0.0
و این‌ها را با نگارش چهار MVC و نگارش دو Razor جایگزین کنید:
System.Web.Mvc, Version=4.0.0.0
System.Web.WebPages, Version=2.0.0.0
System.Web.Helpers, Version=2.0.0.0
System.Web.WebPages.Razor, Version=2.0.0.0
این کارها را با replace in all open documents توسط notepad plus-plus به سادگی می‌توان انجام داد.

4) به روز رسانی مسیرهای قدیمی
به علاوه اگر در پروژه‌های خود از اسمبلی‌های قدیمی به صورت مستقیم استفاده شده:
C:\Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies
C:\Program Files\Microsoft ASP.NET\ASP.NET MVC 3\Assemblies
این‌ها را یافته و به نگارش MVC4 و Razor2 تغییر دهید:
C:\Program Files\Microsoft ASP.NET\ASP.NET Web Pages\v2.0\Assemblies
C:\Program Files\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies

5) به روز رسانی قسمت appSettings فایل‌های کانفیگ
در کلیه فایل‌های web.config برنامه، webpages:Version را یافته و شماره نگارش آن‌را از یک به دو تغییر دهید:
<appSettings>
  <add key="webpages:Version" value="2.0.0.0" />
  <add key="PreserveLoginUrl" value="true" />
</appSettings>
همچنین یک سطر جدید PreserveLoginUrl را نیز مطابق تنظیم فوق اضافه نمائید.

6) رسیدگی به وضعیت اسمبلی‌های شرکت‌های ثالث
ممکن است در این زمان از تعدادی کامپوننت و اسمبلی MVC3 تهیه شده توسط شرکت‌های ثالث نیز استفاده نمائید. برای اینکه این اسمبلی‌ها را وادار نمائید تا از نگارش‌های MVC4 و Razor2 استفاده کنند، نیاز است bindingRedirect‌های زیر را به فایل‌های web.config برنامه اضافه کنید (در فایل کانفیگ ریشه پروژه):
<configuration>
  <!--... elements deleted for clarity ...-->
 
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" 
             publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" 
             publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="4.0.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" 
             publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>
اکنون فایل solution را در VS.NET گشوده و یکبار گزینه rebuild را انتخاب کنید تا پروژه مجددا بر اساس اسمبلی‌های جدید معرفی شده ساخته شود.

7) استفاده از NuGet برای به روز رسانی بسته‌های نصب شده
یک سری از بسته‌های تشکیل دهنده MVC3 مانند موارد ذیل نیز به روز شده‌اند که لازم است از طریق NuGet دریافت و جایگزین شوند:
Unobtrusive.Ajax.2
Unobtrusive.Validation.2
Web.Optimization.1.0.0
و ....

برای اینکار در solution explorer روی references کلیک راست کرده و گزینه Manage NuGet Packages را انتخاب کنید. در صفحه باز شده گزینه updates/all را انتخاب کرده و مواردی را که لیست می‌کند به روز نمائید (شامل جی کوئری، EF، structureMap و غیره خواهد بود).


8) اضافه کردن یک فضای نام جدید
بسته Web Optimization را از طریق NuGet دریافت کنید (برای یافتن آن bundling را جستجو کنید؛ نام کامل آن Microsoft ASP.NET Web Optimization Framework 1.0.0 است). این مورد به همراه پوشه MVC4 نیست و باید از طریق NuGet دریافت و نصب شود. (البته پروژه‌های جدید MVC4 شامل این مورد هستند)
در فایل وب کانفیگ، فضای نام System.Web.Optimization را نیز اضافه نمائید:
    <pages>
      <namespaces>
        <add namespace="System.Web.Optimization" />
      </namespaces>
    </pages>

پس از ارتقاء
اولین مشکلی که مشاهده شد:
بعد از rebuild به مقدار پارامتر salt که به نحو زیر در MVC3 تعریف شده بود، ایراد خواهد گرفت:
[ValidateAntiForgeryToken(Salt = "data123")]
Salt را در MVC4 منسوخ شده معرفی کرده‌اند: (^)
علت هم این است که salt را اینبار به نحو صحیحی خودشان در پشت صحنه تولید و اعمال می‌کنند. بنابراین این یک مورد را کلا از کدهای خود حذف کنید که نیازی نیست.


مشکل بعدی:
در EF 5 جای یک سری از کلاس‌ها تغییر کرده. مثلا ویژگی‌های ForeignKey، ComplexType و ... به فضای نام System.ComponentModel.DataAnnotations.Schema منتقل شده‌اند. در همین حد تغییر جهت کامپایل مجدد کدها کفایت می‌کند.
همچنین فایل‌های پروژه موجود را باز کرده و EntityFramework, Version=4.1.0.0 را جستجو کنید. نگارش جدید 4.4.0.0 است که باید اصلاح شود (این موارد را بهتر است توسط یک ادیتور معمولی خارج از VS.NET ویرایش کنید).
در زمان نگارش این مطلب EF Mini Profiler با EF 5 سازگار نیست. بنابراین اگر از آن استفاده می‌کنید نیاز است غیرفعالش کنید.


اولین استفاده از امکانات جدید MVC4:
استفاده از امکانات System.Web.Optimization که ذکر گردید، می‌تواند اولین تغییر مفید محسوب شود.
برای اینکه با نحوه کار آن بهتر آشنا شوید، یک پروژه جدید MVC4 را در VS.NET (از نوع basic) آغاز کنید. به صورت خودکار یک پوشه جدید را به نام App_Start به ریشه پروژه اضافه می‌کند. داخل آن فایل مثال BundleConfig قرار دارد. این کلاس در فایل global.asax برنامه نیز ثبت شده‌است. باید دقت داشت در حالت دیباگ (compilation debug=true در وب کانفیگ) تغییر خاصی را ملاحظه نخواهید کرد.
تمام این‌ها خوب؛ اما من به نحو زیر از این امکان جدید استفاده می‌کنم:
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.Optimization;

namespace Common.WebToolkit
{
    /// <summary>
    /// A custom bundle orderer (IBundleOrderer) that will ensure bundles are 
    /// included in the order you register them.
    /// </summary>
    public class AsIsBundleOrderer : IBundleOrderer
    {
        public IEnumerable<FileInfo> OrderFiles(BundleContext context, IEnumerable<FileInfo> files)
        {
            return files;
        }
    }

    public static class BundleConfig
    {
        private static void addBundle(string virtualPath, bool isCss, params string[] files)
        {
            BundleTable.EnableOptimizations = true;

            var existing = BundleTable.Bundles.GetBundleFor(virtualPath);
            if (existing != null)
                return;

            var newBundle = isCss ? new Bundle(virtualPath, new CssMinify()) : new Bundle(virtualPath, new JsMinify());
            newBundle.Orderer = new AsIsBundleOrderer();

            foreach (var file in files)
                newBundle.Include(file);

            BundleTable.Bundles.Add(newBundle);
        }

        public static IHtmlString AddScripts(string virtualPath, params string[] files)
        {
            addBundle(virtualPath, false, files);
            return Scripts.Render(virtualPath);
        }

        public static IHtmlString AddStyles(string virtualPath, params string[] files)
        {
            addBundle(virtualPath, true, files);
            return Styles.Render(virtualPath);
        }

        public static IHtmlString AddScriptUrl(string virtualPath, params string[] files)
        {
            addBundle(virtualPath, false, files);
            return Scripts.Url(virtualPath);
        }

        public static IHtmlString AddStyleUrl(string virtualPath, params string[] files)
        {
            addBundle(virtualPath, true, files);
            return Styles.Url(virtualPath);
        }
    }
}
کلاس BundleConfig فوق را به مجموعه کلاس‌های کمکی خود اضافه کنید.
چند نکته مهم در این کلاس وجود دارد:
الف) توسط AsIsBundleOrderer فایل‌ها به همان ترتیبی که به سیستم اضافه می‌شوند، در حاصل نهایی ظاهر خواهند شد. حالت پیش فرض مرتب سازی، بر اساس حروف الفباء است و ... خصوصا برای اسکریپت‌هایی که ترتیب معرفی آن‌ها مهم است، مساله ساز خواهد بود.
ب)BundleTable.EnableOptimizations سبب می‌شود تا حتی در حالت debug نیز فشرده سازی را مشاهده کنید.
ج) متدهای کمکی تعریف شده این امکان را می‌دهند تا بدون نیاز به کامپایل مجدد پروژه، به سادگی در کدهای Razor بتوانید اسکریپت‌ها را اضافه کنید.

 سپس نحوه جایگزینی تعاریف قبلی موجود در فایل‌های Razor با سیستم جدید، به نحو زیر است:
@using Common.WebToolkit

<link href="@BundleConfig.AddStyleUrl("~/Content/blueprint/print", "~/Content/blueprint/print.css")" rel="stylesheet" type="text/css" media="print"/>

@BundleConfig.AddScripts("~/Scripts/js",
                            "~/Scripts/jquery-1.8.0.min.js",
                            "~/Scripts/jquery.unobtrusive-ajax.min.js",
                            "~/Scripts/jquery.validate.min.js")

@BundleConfig.AddStyles("~/Content/css",
                            "~/Content/Site.css",
                            "~/Content/buttons.css")
پارامتر اول این متدها، سبب تعریف خودکار routing می‌شود. برای مثال اولین تعریف، آدرس خودکار زیر را تولید می‌کند:
http://site/Content/blueprint/print?v=hash
بنابراین تعریف دقیق آن مهم است. خصوصا اگر فایل‌های شما در پوشه‌ها و زیرپوشه‌های متعددی قرار گرفته نمی‌توان تمام آن‌ها را در طی یک مرحله معرفی نمود. هر سطح را باید از طریق یک بار معرفی به سیستم اضافه کرد. مثلا اگر یک زیر پوشه به نام noty دارید (Content/noty)، چون در یک سطح و زیرپوشه مجزا قرار دارد، باید نحوه تعریف آن به صورت زیر باشد:
@BundleConfig.AddStyles("~/Content/noty/css",
                                "~/Content/noty/jquery.noty.css",
                                "~/Content/noty/noty_theme_default.css")
این مورد خصوصا در مسیریابی تصاویر مرتبط با اسکریپت‌ها و شیوه نامه‌ها مؤثر است؛ وگرنه این تصاویر تعریف شده در فایل‌های CSS یافت نخواهند شد (تمام مثال‌های موجود در وب با این مساله مشکل دارند و فرض آن‌ها بر این است که کلیه فایل‌های خود را در یک پوشه، بدون هیچگونه زیرپوشه‌ای تعریف کرده‌اید).
پارامترهای بعدی، محل قرارگیری اسکریپت‌ها و CSSهای برنامه هستند و همانطور که عنوان شد اینبار با خیال راحت می‌توانید ترتیب معرفی خاصی را مدنظر داشته باشید؛ زیرا توسط AsIsBundleOrderer به صورت پیش فرض لحاظ خواهد شد.