اشتراک‌ها
نحوه تغییر سایز تصاویر در صفحات Responsive
در صورت اسفاده از این روش تصاویر به صورت خودکار در صفحات responsive   تغییر سایز می‌دهند و سرعت بارگذاری در سخت افزار‌های مختلف بهبود می‌یابد .
نحوه تغییر سایز تصاویر در صفحات Responsive
اشتراک‌ها
الگوی طراحی singleton درسی شارپ

الگو‌های طراحی در طراحی نرم افزار و سیستم‌های نرم افزاری نقشی پر رنگ را دارند که یکی از مشهورترین آنها الگوی یگانگی یا Singleton  می‌باشد که در این اشتراک حالت‌های مختلف بررسی و پیاده سازی شده است

الگوی طراحی singleton  درسی شارپ
مطالب
تگ گذاری در کامنت‌ها
در محیط‌های برنامه نویسی مدرن و امروزی، استفاده از تگ‌ها در کامنت‌ها (CommentTag) رواج بسیاری دارد که یکی از معروفترین این تگ‌ها، تگ TODO است. این نوع تگ‌ها که عموما به همراه یک توضیح کوتاه یا عنوان به کار می‌روند، برای این است که بتوانیم از طریق ابزارهایی که ادیتورها در اختیارمان قرار می‌دهند، آن‌ها را پیدا کنیم. حتی در سیستم‌های لینوکسی میتوان با دستور Grep به جست و جوی آن‌ها پرداخت. عموما تگ‌ها با حروف بزرگ نوشته می‌شوند؛ ولی اجباری در آن نیست ولی رعایت آن بهتر است. نام‌های دیگری که برای این تگ‌ها به کار می‌رود Token و Codetag می‌باشد. از معروفترین تگ ها، می‌توان به تگ‌های زیر اشاره کرد:

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

FIXME : این نوع تگ همانند بالاست، ولی اجبار بیشتری در اصلاح از خود نشان میدهد و ترتیب و اهمیت بالاتری دارد. عموما کدهایی که با این نوع کامنت‌ها مزین می‌شوند، دارای طراحی بد یا موقتی هستند که باید در آینده آن‌ها را اصلاح کرد.

UNDONE : این تگ برای اصلاح یا تغییر نیست. ولی به شما میگوید که قبلا این کد چگونه بوده است و چه تغییراتی کرده است.  قبلا چه چیزهایی در کد پیاده سازی شده بوده است که الان در کد وجود ندارد و چرا حذف شده است.

HACK : گاهی اوقات در کدها، باگ هایی رخ میدهند که مجبور به استفاده از راه‌های غیرعادی برای رفع آن می‌شوید. این نوع روش‌های رفع مشکل، روش‌ها و راه حل‌های مناسبی نیستند؛ ولی می‌توانند به طور موقت و در زمان سریعتری پاسخگوی ما باشند. برنامه نویس بعد از رفع مشکل، با درج این نوع کامنت، در آینده به خود یادآوری میکند که این کد نیاز به راه حل مناسب‌تری دارد.
 
BUGBUG : این کامنت توسط برنامه نویس کد مربوطه درج می‌شود و مربوط به زمانی است که برنامه نویس کد را نوشته است، ولی اطمینانی از صحت آن ندارد. پس برنامه نویس نیاز دارد اطلاعات بیشتری را در مورد این مسئله بیابد.
    // BUGBUG: I'm sure these GUIDs are defined somewhere but I'm not sure which library contains them, so defining them here.
    DEFINE_GUID(IID_IFoo, 0x12345678,0x1234,0x1234,0x12,0x12,0x12,0x12,0x12,0x12,0x12,0x12);

XXX :  به برنامه نویس هشدار می‌دهد که این کد راه حل‌های نادرستی دارد و احتمالا بر اساس اطلاعات نادرستی این کد شکل گرفته است، ولی در حال حاضر کار میکند.

در ویژوال استادیو، پنل taskList برای نمایش این تگ‌ها به کار می‌رود و از تگ‌های HACK,UNDONE و TODO به طور پیش فرض پشتیبانی می‌کند. در صورتی که تمایل دارید تگ‌های اضافه‌تری داشته باشید یا ترتیب اولویت نمایش تگ‌ها در پنل taskList را تغییر دهید، مسیر زیر را طی کنید:
Tools>Options>Environment>Task List

در اندروید استادیو هم دو تگ اول لیست پشتیبانی می‌شوند. در اندروید استادیو شما می‌توانید برای todo هایتان الگو و فیلتر تعریف کنید. برای اینکار ابتدای ادیتور را باز کرده و در بخش Editor گزینه Todo را انتخاب کنید. در لیست بالا می‌توانید یک نمونه الگو برای todo خاص خود اضافه کنید. به عنوان مثال تگ‌های نامبرده در بالا را اضافه کنید و برای آن آیکن و نحوه رنگبندی و قلم و ... را برای نمایش آن انتخاب کنید.


در لیست پایینی که بخش فیلترهاست، میتوانید یک فیلتر را تعریف کنید تا بر اساس این فیلتر مشخص کنید که چه todo هایی نمایش یابند. برای فیلتر کردن در در پنل todo، در نوار ابزار، آیکن قیفی شکل را کلیک کند تا لیست فیلترها نمایش یابند.

نحوه صحیح قرار دادن یک todo به شکل زیر است:

// TODO:2008-12-06:johnc:Add support for negative offsets.
// While it is unlikely that we get a negative offset, it can
// occur if the garbage collector runs out of space.
بعد از ذکر نام تگ، تاریخ را بر اساس سال، ماه و روز وارد کرده و سپس نام شخصی که این کامنت را قرار داده است و در ادامه عنوان مناسبی را که گویای مطلب باشد، انتخاب کنید. در خط‌های بعدی هم توضیح کوتاهی که مدنظر شماست. در این حالت با استفاده از ابزار unix grep میتوانید گزارش گیری مناسبی هم داشته باشید.
مطالب
Closure در JavaScript
در قسمت قبلی درباره علت نیاز به الگوهای طراحی در JavaScript و Function Spaghetti code صحبت شد. در این قسمت Closure در JavaScript مورد بررسی قرار می‌گیرد. 
در JavaScript می‌توان توابع تو در تو نوشت (nested functions) ، زمانی که یک تابع درون تابع دیگر تعریف می‌شود تابع درونی به تمام متغیر‌ها و توابع تابع بیرونی (Parent) دسترسی دارد.
Douglas Crockford برای تعریف Closure می‌گوید : 

an inner function always has access to the vars and parameters of its outer function, even after the outer  function has returned

یک تابع درونی (nested) همیشه به متغیر‌ها و پارامتر‌ها تابع بیرونی دسترسی دارد ، حتی اگر تابع بیرونی مقدار برگردانده باشد. 

تابع زیر را در نظر بگیرید : 
// The getDate() function returns a nested function which refers the 'date' variable defined
// by outer function getDate()
function getDate() {
   var date = new Date();    // This variable stays around even after function returns

   // nested function
   return function () {
      return date.getMilliseconds();
   }
}

  اکنون اگر به صورت زیر تابع getDate فراخوانی شود مشاهده می‌شود که تابع درونی (با کامنت nested function مشخص شده است.) به شیء date دسترسی دارد.
// Once getDate() is executed the variable date should be out of scope and it is, but since
// the inner function
// referenes date, this value is available to the inner function.
var dt = getDate();

alert(dt());
alert(dt());
خروجی هر 2 alert یک مقدار خواهد بود. 
اگر از فردی که به تازگی رو به JavaScript آورده است خواسته شود تابعی بنویسد که میلی ثانیه‌ی زمان جاری را برگداند احتمالا همچین کدی تحویل می‌دهد : 
        function myNonClosure() {
            var date = new Date();
            return date.getMilliseconds();
        }
در کد بالا پس از اجرای myNonClosure متغیر date از بین خواهد رفت ، این مسئله در دنیای JavaScript طبیعی هست.
این مثال را در نظر بگیرید :  
var MyDate = function () {
    var date = new Date();
    var getMilliSeconds = function () {
        return date.getMilliseconds();
    }
}

var dt = new MyDate();

alert(dt.getMilliSeconds());  // This will throw error as getMilliSeconds is not accessible.
در صورت اجرای مثال بالا خطایی با این مضمون دریافت خواهد شد که getMilliSeconds دستیابی پذیر نیست. (کپسوله شده)  برای اینکه آن را دستیابی پذیر کنیم کد را به این صورت تغییر می‌دهیم :
// This is closure 
var MyDate = function () {
    var date = new Date();   // variable stays around even after function returns
    var getMilliSeconds = function () {
        return date.getMilliseconds();
    };
    return {
        getMs : getMilliSeconds
    }
}
آنچه در تابع بالا انجام شده کپسوله سازی همه‌ی منطق کار (منطق کار در اینجا برگرداندن میلی ثانیه زمان جاری می‌باشد) در یک فضای نام به نام MyDate می‌باشد. همچنین فقط متد‌های عمومی در اختیار استفاده کننده این تابع قرار داده شده است. برای استفاده می‌توان بدین صورت عمل کرد : 
var dt = new MyDate();
alert(dt.getMs());  // This should work.
در کد بالا برای توابع و متغیر‌های درونی یک container ایجاد کردیم که باعث جلوگیری از تداخل در نام متغیر‌ها با دیگر کد‌ها خواهد شد . (برای مشاهده‌ی تداخل‌ها به قسمت قبلی  توجه کنید.)
اگر بخواهیم Closure را تشبیه کنیم ، Closure شبیه به کلاس‌ها در C# یا Java هست. 
Closure یک حوزه (scope) برای متغیر‌ها و توابع درونی خودش ایجاد می‌کند.
jQuery بهترین مثال کاربردی برای Closure می‌باشد : 
(function($) {

    // $() is available here

})(jQuery);
در ادامه این مفاهیم بیشتر توضیح داده می‌شودند ، اکنون می‌خواهیم مشکلی که در قسمت قبلی مطرح کردیم به کمک Closure حل کنیم : 
 در آن مثال گفته شد که اگر : 
// file1.js
function saveState(obj) {
    // write code here to saveState of some object
    alert('file1 saveState');
}
// file2.js (remote team or some third party scripts)
function saveState(obj, obj2) {
     // further code...
    alert('file2 saveState");
}
اگر تابعی به نام saveState در 2 فایل مختلف داشته باشیم و این 2 فایل را بدین صورت در برنامه آدرس دهیم : 
<script src="file1.js" type="text/javascript"></script>
<script src="file2.js" type="text/javascript"></script>
تابع saveState در فایل دوم تابع saveState فایل اول را override می‌کند. یک از توابع بالا را به صورت زیر باز نویسی می‌کنیم و منطق کار را کپسوله می‌کنیم : 
function App() {
    var save = function (o) {
        // write code to save state here..
        // you have acces to 'o' here...
        alert(o);
    };

    return {
        saveState: save
    };
}
بدون نگرانی تداخل saveState با بقیه saveState‌ها در هر پلاگین یا فایل دیگری می‌توان از saveState می‌توان اینگونه استفاده کرد : 
var app = new App();

app.saveState({ name: "rajesh"});
برای اطلاعات بیشتر در مورد Closure ها این لینک  را بررسی کنید.
مطالب
آشنایی با Fluent interfaces

تعریف مقدماتی fluent interface در ویکی پدیا به شرح زیر است: (+)

In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is a way of implementing an object oriented API in a way that aims to provide for more readable code.

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

برای مثال:
using System;

namespace FluentInt
{
public class FluentApiTest
{
private int _val;

public FluentApiTest Number(int val)
{
_val = val;
return this;
}

public FluentApiTest Abs()
{
_val = Math.Abs(_val);
return this;
}

public bool IsEqualTo(int val)
{
return val == _val;
}
}
}
مثالی هم از استفاده‌ی آن به صورت زیر می‌تواند باشد:
if (new FluentApiTest().Number(-10).Abs().IsEqualTo(10))
{
Console.WriteLine("Abs(-10)==10");
}
که در آن توانستیم تمام متدها را زنجیر وار و با خوانایی خوبی شبیه به نوشتن جملات انگلیسی در کنار هم قرار دهیم.
خوب! این مطلبی است که همه جا پیدا می‌کنید و مطلب جدیدی هم نیست. اما موردی را که سخت می‌شود یافت این است که طراحی کلاس فوق ایراد دارد. برای مثال شما می‌توانید ترکیب‌های زیر را هم تشکیل دهید و کار می‌کند؛ یا به عبارتی برنامه کامپایل می‌شود و این خوب نیست:
if(new FluentApiTest().Abs().Number(-10).IsEqualTo(10)) ...
if (new FluentApiTest().Abs().IsEqualTo(10)) ...
می‌شود در کدهای برنامه یک سری throw new exception را هم قرار داد که ... هی! اول باید اون رو فراخوانی کنی بعد این رو!
ولی ... این روش هم صحیح نیست. از ابتدای کار نباید بتوان متد بی‌ربطی را در طول این زنجیره مشاهده کرد. اگر قرار نیست استفاده گردد، نباید هم در intellisense ظاهر شود و پس از آن هم نباید قابل کامپایل باشد.

بنابراین صورت مساله به این ترتیب اصلاح می‌شود:
می‌خواهیم پس از نوشتن FluentApiTest و قرار دادن یک نقطه، در intellisense فقط Number ظاهر شود و نه هیچ متد دیگری. پس از ذکر متد Number فقط متد Abs یا مواردی شبیه به آن مانند Sqrt ظاهر شوند. پس از انتخاب مثلا Abs آنگاه متد IsEqualTo توسط Intellisense قابل دسترسی باشد. در روش اول فوق، به صورت دوستانه همه چیز در دسترس است و هر ترکیب قابل کامپایلی را می‌شود با متدها ساخت که این مورد نظر ما نیست.
اینبار پیاده سازی اولیه به شرح زیر تغییر خواهد کرد:
using System;

namespace FluentInt
{
public class FluentApiTest
{
public MathMethods<FluentApiTest> Number(int val)
{
return new MathMethods<FluentApiTest>(this, val);
}
}

public class MathMethods<TParent>
{
private int _val;
private readonly TParent _parent;

public MathMethods(TParent parent, int val)
{
_val = val;
_parent = parent;
}

public Restrictions<MathMethods<TParent>> Abs()
{
_val = Math.Abs(_val);
return new Restrictions<MathMethods<TParent>>(this, _val);
}
}

public class Restrictions<TParent>
{
private readonly int _val;
private readonly TParent _parent;

public Restrictions(TParent parent, int val)
{
_val = val;
_parent = parent;
}

public bool IsEqualTo(int val)
{
return _val == val;
}
}
}
در اینجا هم به همان کاربرد اولیه می‌رسیم:
if (new FluentApiTest().Number(-10).Abs().IsEqualTo(10))
{
Console.WriteLine("Abs(-10)==10");
}
با این تفاوت که intellisense هربار فقط یک متد مرتبط در طول زنجیره را نمایش می‌دهد و تمام متدها در همان ابتدای کار قابل انتخاب نیستند.
در پیاده سازی کلاس MathMethods از Generics استفاده شده به این جهت که بتوان نوع متد Number را بر همین اساس تعیین کرد تا متدهای کلاس MathMethods در Intellisense (یا به قولی در طول زنجیره مورد نظر) ظاهر شوند. کلاس Restrictions نیز به همین ترتیب معرفی شده است و از آن جهت تعریف نوع متد Abs استفاده کردیم. هر کلاس جدید در طول زنجیره، توسط سازنده خود به وهله‌ای از کلاس قبلی به همراه مقادیر پاس شده دسترسی خواهد داشت. به این ترتیب زنجیره‌ای را تشکیل داده‌ایم که سازمان یافته است و نمی‌توان در آن متدی را بی‌جهت پیش یا پس از دیگری صدا زد و همچنین دیگر نیازی به بررسی نحوه‌ی فراخوانی‌های یک مصرف کننده نیز نخواهد بود زیرا برنامه کامپایل نمی‌شود.
مطالب
پیاده سازی الگوی طراحی Memento

Memento یک الگوی طراحی مفید و ساده است که برای ذخیره و بازیابی state یک object استفاده می‌شود. در بعضی از مقالات از آن به عنوان snapshot نیز یاد شده است! اگر با git  کار کرده باشید، این مفهوم را می‌توان در git بسیار یافت؛ هر commit به عنوان یک snapshot میباشد که میتوان به صورت مکرر آن را undo کرد و یا مثال خیلی ساده‌تر میتوان به ctrl+z در سیستم عامل اشاره کرد.

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

Int temp;
Int a=1;
temp=a;
a=2;
.
.
a=temp;

شما قطعا در برنامه نویسی با کد بالا زیاد برخورد داشته‌اید و آن‌را به صورت مکرر انجام داده‌اید. کد بالا را در قالب یک object بیان میکنیم. به مثال زیر توجه کنید:

int main()
{
  MyClass One = new MyClass();
  MyClass Temp = new MyClass();
  // Set an initial value.
  One.Value = 10;
  One.Name = "Ten";
  // Save the state of the value.
  Temp.Value = One.Value;
  Temp.Name = One.Name;
  // Change the value.
  One.Value = 99;
  One.Name = "Ninety Nine";
  // Undo and restore the state.
  One.Value = Temp.Value;
  One.Name = Temp.Name;
}

در کد بالا با استفاده از یک temp، شیء مورد نظر را ذخیره کرده و در آخر مجدد داده‌ها را درون شیء، restore  میکنیم.


 از مشکلات کد بالا میتوان گفت :

۱- برای هر object باید یک شیء temp ایجاد کنیم.

۲- ممکن است بخواهیم که حالات یک object را بر روی هارد ذخیره کنیم. با روش فوق کدها خیلی پیچیده‌تر خواهند شد.

۳- نوشتن کد به این سبک برای پروژه‌های بزرگ، پیچیده و مدیریت آن سخت‌تر می‌شود.


پیاده سازی memento

ما این مثال را در قالب یک پروژه NET Core  onsole. ایجاد میکنیم. برای این کار یک پوشه‌ی جدید را ایجاد و درون ترمینال دستور زیر را وارد کنید:

dotnet new console

روش‌های زیادی برای پیاده سازی memento وجود دارند. برای پیاده سازی memento ابتدا یک abstract class را به شکل زیر ایجاد میکنیم: 

abstract class MementoBase
{
  protected Guid mementoKey = Guid.NewGuid();
  abstract public void SaveMemento(Memento memento);
  abstract public void RestoreMemento(Memento memento);
}

اگر به کلاس بالا دقت کنید، این کلاس قرار است parent کلاس‌های دیگری باشد که داری دو متد SaveMemento و RestoreMemento برای ذخیره و بازیابی و همچنین یک Guid برای نگهداری state‌های مختلف میباشد.

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

class Memento
{
    private Dictionary<Guid, object> stateList = new Dictionary<Guid, object>();
    public object GetState(Guid key)
    {
        return stateList[key];
    }
    public void SetState(Guid key, object newState)
    {
        stateList[key] = newState;
    }
    public Memento()
    {
    }
}

در کد بالا با یک Dictionary می‌توان هر object را با کلیدش ذخیره کنیم. توجه کنید که value دیکشنری از نوع object میباشد و چون object پدر تمام object‌های دیگر است پس می‌توانیم هر نوع داده‌ای را در آن ذخیره کنیم. تا اینجا، Memento پیاده سازی شده است. میتوان این کار را با جنریک‌ها نیز پیاده سازی کرد.

در ادامه می‌خواهیم یک کلاس بسازیم و حالت‌های مختلف را در آن بررسی کنیم. کلاس زیر را ایجاد کنید:

class ConcreteOriginator : MementoBase
{
  private int value = 0;
  public ConcreteOriginator(int newValue)
  {
    SetData(newValue);
  }
  public void SetData(int newValue)
  {
    value = newValue;
  }
  public void Speak()
  {
    Console.WriteLine("My value is " + value.ToString());
  }
  public override void SaveMemento(Memento memento)
  {
    memento.SetState(mementoKey, value);
  }
  public override void RestoreMemento(Memento memento)
  {
    int restoredValue = (int)memento.GetState(mementoKey);
    SetData(restoredValue);
  }
}

کلاس ConcreteOriginator از کلاس MementoBase ارث بری کرده و دو متد RestoreMemento و SaveMemento را پیاده سازی میکند و همچنین دارای یک مشخصه value می‌باشد. برای خروجی گرفتن، متد main را به صورت زیر پیاده سازی می‌کنیم:

static void Main(string[] args)
{
  Memento memento = new Memento();
  // Create an originator, which will hold our state data.
  ConcreteOriginator myOriginator = new ConcreteOriginator("Hello World!", StateType.ONE);
  ConcreteOriginator anotherOriginator = new ConcreteOriginator("Hola!", StateType.ONE);
  ConcreteOriginator2 thirdOriginator = new ConcreteOriginator2(7);
  // Set some state data.
  myOriginator.Speak();
  anotherOriginator.Speak();
  thirdOriginator.Speak();
  // Save the states into our memento.
  myOriginator.SaveMemento(memento);
  anotherOriginator.SaveMemento(memento);
  thirdOriginator.SaveMemento(memento);
  // Now change our originators' states.
  myOriginator.SetData("Goodbye!", StateType.TWO);
  anotherOriginator.SetData("Adios!", StateType.TWO);
  thirdOriginator.SetData(99);
  myOriginator.Speak();
  anotherOriginator.Speak();
  thirdOriginator.Speak();
  // Restore our originator's state.
  myOriginator.RestoreMemento(memento);
  anotherOriginator.RestoreMemento(memento);
  thirdOriginator.RestoreMemento(memento);
  myOriginator.Speak();
  anotherOriginator.Speak();
  thirdOriginator.Speak();
  Console.ReadKey();
}
تا خط ۱۲، مراحل عادی کد نویسی را پیش رفته‌ایم. در خطوط ۱۳ تا ۱۵، داده را در Memento ذخیره میکنیم. در خطوط ۱۷ تا ۱۹، داده‌های اشیاء را با استفاده از متد SetData عوض میکنیم. در خطوط ۲۰ تا ۲۲ با متد Speak، مقدار value را نمایش میدهیم و در خطوط ۲۴ تا ۲۶، داده‌ها را Restore میکنیم و در آخر دوباره مقدار value را نمایش میدهیم.
برنامه را اجرا کنید .خروجی به شکل زیر خواهد بود:
Hello World! I'm in state ONE
Hola! I'm in state ONE
My value is 7
Goodbye! I'm in state TWO
Adios! I'm in state TWO
My value is 99
Hello World! I'm in state ONE
Hola! I'm in state ONE
My value is 7
مطالب
آشنایی با الگوی 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 جهت استفاده از این خاصیت اندکی تغییر کرده است.

ماخذ

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

همانطور که بیان کردیم، کامنت گذاری یکی از مهم‌ترین کارهایی است که یک برنامه نویس انجام می‌دهد. به خصوص زمانیکه به صورت تیمی کار می‌کنید، این امر مهم‌تر از قبل خود را نشان می‌دهد. بسیاری از برنامه نویسان که بیشتر دلیل آن تنبلی است، از این کار سرباز می‌زنند و ممکن است آن را اتلاف وقت بدانند. ولی با کامنت گذاری فهم و درک کد، در آینده بالا‌تر می‌رود. در مقاله‌ی تخصصی «هنر کامنت نویسی» نوشته‌ی «برنهارد اسپویدا» بهانه‌های جالبی از برنامه نویسان را برای سرباز زدن از اینکار، ذکر شده است؛ به عنوان نمونه:
من کدم را به خوبی متوجه می‌شوم.
کد خوب، خودش گویای همه چیز هست.
وقتی برای کامنت نویسی وجود ندارد. باید چسبید به کد.


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


سطوح کامنت نویسی بر سه نوع هستند:

Documentary Comments:
این مستند سازی در سطح یک سند مثل فایل یا به خصوص یک پروژه رخ می‌دهد که شامل اطلاعات و تاریخچه‌ی آن سند است که این اطلاعات به شرح زیر هستند:

 File Name   نام سند
 File Number/Version Number   شماره نسخه آن سند
 Creation Date   تاریخ ایجاد آن
 Last Modification Date
 تاریخ آخرین تغییر سند
 Author's Name
 سازنده‌ی سند
 Copyright Notice
 اطلاعاتی در مورد کپی رایت سند
 Purpose Of Program
 هدف کاری برنامه. یک خلاصه از آن چه برنامه انجام می‌دهد.
 Change History
 لیستی از تغییرات مهمی که در جریان ایجاد آن رخ داده است.
 Dependencies  وابستگی‌های سند. بیشتر در سطح پروژه معنا پیدا می‌کند؛ مانند نمونه‌ی آن برای سایت جاری که به صورت عمومی منتشر شده است.
 Special Hardware Requirements
 سخت افزار مورد نیاز برای اجرای برنامه. حتی قسمتی می‌تواند شامل نیازمندی‌های نرم افزاری هم باشد.
نمونه ای از این مستند سازی برای برنامه ای که به زبان پاسکال نوشته شده است:
PCMBOAT5.PAS*************************************************************
**
File: PCMBOAT5.PAS
Author: B. Spuida
Date: 1.5.1999
Revision: 
1.1 
PCM-DAS08 and -16S/12 are supported.
Sorting routine inserted.
Set-files are read in and card as well as
amplification factor are parsed.

1.1.1
Standard deviation is calculated.

1.1.2
Median is output. Modal value is output.

1.1.4
Sign in Set-file is evaluated.
Individual values are no longer output.
(For tests with raw data use PCMRAW.EXE)

To do:
outliers routine to be revised.
Statistics routines need reworking.
Existing Datafile is backed up.

Purpose: 
Used for measurement of profiles using the
Water-SP-probes using the amplifier andthe PCM-DAS08-card, values are acquired
with n = 3000. Measurements are taken in 1
second intervals. The values are sorted using
Quicksort and are stacked "raw" as well as after
dismissing the highest and lowest 200 values as
'outliers'.


Requirements:
The Card must have an A/D-converter.
Amplifier and probes must be connected.
Analog Signal must be present.
CB.CFG must be in the directory specified by the
env-Variable "CBDIREC" or in present directory.

در بالا، خصوصیت کپی رایت حذف شده است. دلیل این امر این است که این برنامه برای استفاده در سطح داخلی یک شرکت استفاده می‌شود.


Functional Comments: کامنت نویسی در سطح کاربردی به این معنی نیست که شما اتفاقاتی را که در یک متد یا کلاس یا هر بخشی روی می‌دهد، خط به خط توضیح دهید؛ بلکه چرخه‌ی کاری آن شی را هم توضیح بدهید کفایت می‌کند. این مورد می‌تواند شامل این موارد باشد:
  • توضیحی در مورد باگ‌های این قسمت
  • یادداشت گذاری برای دیگر افراد تیم
  • احتمالاتی که برای بهبود ویژگی‌ها و کارایی کد وجود دارد.


Explanatory Comment: کامنت گذاری توصیفی در سطح کدنویسی رخ می‌دهد و شامل توضیح در مورد کارکرد یک شیء و توضیح کدهای شیء مربوطه می‌گردد. برای قرار دادن کامنت الزامی نیست که کدها را خط به خط توضیح دهید یا اینکه خطوط ساده را هم تشریح کنید؛ بلکه کامنت شما همینقدر که بتواند نحوه‌ی کارکرد هر چند خط کد مرتبط به هم را هم توضیح دهد، کافی است. این توضیح‌ها بیشتر شامل موارد زیر می‌شوند:

  • کدهای آغازین
  • کدهای خروجی
  • توضیح کوتاه از آنچه که این شیء ، متد یا ... انجام می‌دهد. 
  • حلقه‌های طولانی یا پیچیده
  • کدهای منطقی عجیب و پیچیده
  • Regular Expression

کدهای آغازین شروع خوبی برای تمرین خواهند بود. به عنوان نمونه اینکه توضیحی در مورد ورودی و خروجی یک متد بدهید که آرگومان‌های ورودی چه چیزهایی هستند و چه کاربری داردند و در آغاز برنامه، برنامه چگونه آماده سازی و اجرا می‌شود. مقادیر پیش فرض چه چیزهایی هستند و پروژه چگونه تنظیم و مقداردهی می‌شود.

کدهای خروجی هم به همین منوال است. خروجی‌های نرمال و غیرنرمال آن چیست؟ کدهای خطایی که ممکن است برگرداند و ... که باید به درستی توضیح داده شوند.

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

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

سیستم کامنت گذاری
هر زبانی از یک سیستم خاص برای کامنت گذاری استفاده می‌کند. به عنوان مثال پرل از سیستم (POD (Plain Old Documentation استفاده می‌کند یا برای Java سیستم JavaDoc یا برای PHP از سیستم PHPDoc  (+ ) که پیاده سازی از JavaDoc می‌باشد استفاده می‌کنند. این سیستم برای سی شارپ استفاده از قالب XML است. کد زیر نمونه‌ای از استفاده از این سیستم است:
// XMLsample.cs
// compile with: /doc:XMLsample.xml
using System;
/// <summary>
/// Class level summary documentation goes here.</summary>
/// <remarks>
/// Longer comments can be associated with a type or member
/// through the remarks tag</remarks>
public class SomeClass
{
    /// <summary>
    /// Store for the name property</summary>
    private string myName = null;

    /// <summary>
    /// The class constructor. </summary>
    public SomeClass()
    {
        // TODO: Add Constructor Logic here
    }

    /// <summary>
    /// Name property </summary>
    /// <value>
    /// A value tag is used to describe the property value</value>
    public string Name
    {
        get
        {
            if (myName == null)
            {
                throw new Exception("Name is null");
            }
            return myName;
        }
    }

    /// <summary>
    /// Description for SomeMethod.</summary>
    /// <param name="s"> Parameter description for s goes here</param>
    /// <seealso cref="String">
    /// You can use the cref attribute on any tag to reference a type or member
    /// and the compiler will check that the reference exists. </seealso>
    public void SomeMethod(string s)
    {
    }
}

دستورات سیستم کامنت گذاری سی شارپ

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