State Pattern

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

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

برای مثال فرضی کنید با یک برنامه مانند Windows Media Player، در حال دیدن یک فیلم هستید. این برنامه دکمه های مانند Play، Pause و Stop دارد که با کلیک روی آنها می توانید برنامه را به حالت همنام با آن دکمه ببرید. پس برای این شی، سه حالت بالا را می توانید در نظر بگیرید. حال تصویر کنید که یک برنامه شبیه به مثال بالا را خودمان می خواهیم بنویسیم. یکی  از شیوه ها برای انجام این کار می تواند به این ترتیب باشد که ما در ابتدا تمام حالاتی را که یک شی Media Player، می تواند قبول کند را جمع آوری می کنیم. در مرحله دوم برای هر حالت یک متغییر تعریف می کنیم و مقادیر مربوط به آنها را مشخص می کنیم و علاوه بر اینها یک متغییر برای نگهداری حالت فعلی شی در نظر می گیریم.

const int play=0;

const int stop=1;

const int pause=2;

int state = stop; //حالت اولیه

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

public void  Stop()

{

if (state == play)

   {

    //عملیات مورد نظر

   }

if (state == pause)

   {

    //عملیات مورد نظر

   }

if (state == stop)

   {

    //عملیات مورد نظر

   }

}

روش بالا می تواند  برای پیاده سازی یک شی که دارای چندین حالت است به کار برود. ولی تصور کند که یک حالت جدید را بخواهیم به شی اضافه کنیم و یا در نحوه عملکرد شی در یک حالت خاص تغییر دهیم مطمئنا کار مشکلی را خواهیم داشت.

یک روش خوب و کارا برای پیاده سازی اشیای که در طول حیات خود می توانند چندین حالت مختلف داشته باشند، می تواند چگونه باشد؟ شاید شما پاسخ های خوب و بهتری بتوانید ارائه کنید. ولی یکی از روش ها می تواند به صورت زیر باشد:

۱٫       در ابتدا یک اینترفیس به نام state تعریف می کنیم که شامل یک متد برای هر عملی است که شی مورد نظر می تواند انجام دهد.

۲٫       در مرحله دوم برای هر حالت شی یک کلاس تعریف می کنیم که اینترفیس state را پیاده سازی می کند. در واقع این کلاس مسول پاسخگویی به رویدادها است. زمانیکه  شی در این حالت قرار دارد.

 

برای نمونه در همان مثال Media Player،  در ابتدا ما یک کلاس اینترفیس به نام state تعریف می کنیم. سپس برای هر حالت یک کلاس تعریف می کنیم که اینترفیس state را پیاده سازی می کند. برای پیاده سازی هر حالت ما نیاز داریم  تا رفتار هر کلاس را مشخص کنیم هنکامیکه هر عمل فرا خوانی می شود.

 

 

بعد از پیاده سازی تمام حالات شی مورد نظر، به کلاس اصلی یا همان کلاس شی مورد نظر (Media Player) می رسیم. این کلاس همان متد های روش اول را خواهد داشت اما با چندین تفاوت:

۱٫       به جای استفاده از متغییرهای عددی برای هر حالت و حالت فعلی، از اشیاء که برای حالت ها تعریف کردیم استفاده می کنیم.

 

کد جدید

کد قدیمی

public class MediaPlayer{

State MediaState;

PlayState playstate;

PauseState pausestate;

StopState stopstate;

MediaPlayer{

playstate = new PlayState();

 new PauseState ();=  pausestate

stopstate = new StopState();

MediaState = stopstate;

}

 

Public class MediaPlayer{

const int play=0;

const int stop=1;

const int pause=2;

MediaPlayer{

const int state = stop; //حالت اولیه

}

 

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

public void  Stop()

{

MediaState.stop();

}

چون MediaState اشاره گر به حالت فعلی است. متد stop حالت فعلی اجاره خواهد شد بدون هیچ جمله ی شرطی.

  

نمودار الگوی حالت (State Pattern):

ما  تا اینجا یک الگوی حالت را بطور کامل پیاده سازی کردیم. ولی دوباره نکات بالا را باهم بررسی می کنیم.

۱٫       رفتار یک شی توسط حالت داخلی آن شی مشخصی می شود که در مقابل رخ دادن یک رویداد می تواند تغییر کند.

۲٫       تعداد حالات یک شی را باید بتوانیم افزایش بدهیم بدون اینکه مجبور باشیم قسمت های زیادی از کد را مرور کنیم یا تغییر دهیم.

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

  

 

کلاس Context کلاسی است که می تواند دارای چندین حالت داخلی باشد در مثال ما همان Media Player.

اینترفیس State یک اینترفیس مشترک برای همه حالت ها تعریف می کند.

کلاس های Concrete، عمل های را که شی در آن حالت انجام می دهد، پیاده سازی می کنند.(کلاسهای PlayState, StopState,PauseState)

 

  1. ۱۹ بهمن ۱۳۸۵ در ۱۱:۲۲ | #1

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

  2. faezeh aarabi
    ۲۵ فروردین ۱۳۸۶ در ۰۱:۴۵ | #2

    سلام میشه درباره context بیشتر توضیح بدین؟

  1. بدون بازتاب