۱۳۹۰/۰۷/۲۸

آشنايي با Refactoring - قسمت 10


يكي ديگر از روش‌هايي كه جهت بهبود كيفيت كدها مورد استفاده قرار مي‌گيرد، «طراحي با قراردادها» است؛ به اين معنا كه «بهتر است» متدهاي تعريف شده پيش از استفاده از آرگومان‌هاي خود، آن‌ها را دقيقا بررسي كنند و به اين نوع پيش شرط‌ها، قرارداد هم گفته مي‌شود.
نمونه‌اي از آن‌را در قسمت 9 مشاهده كرديد كه در آن اگر آرگومان‌هاي متد AddRole، خالي يا نال باشند، يك استثناء صادر مي‌شود. اين نوع پيغام‌هاي واضح و دقيق در مورد عدم اعتبار ورودي‌هاي دريافتي، بهتر است از پيغام‌هاي كلي و نامفهوم null reference exception كه بدون بررسي stack trace و ساير ملاحظات، علت بروز آن‌ها مشخص نمي‌شوند.
در دات نت 4، جهت سهولت اين نوع بررسي‌ها، مفهوم Code Contracts ارائه شده است. (اين نام هم از اين جهت بكارگرفته شده كه Design by Contract نام تجاري شركت ثبت شده‌اي در آمريكا است!)


يك مثال:
متد زير را در نظر بگيريد. اگر divisor مساوي صفر باشد، استثناي كلي DivideByZeroException صادر مي‌شود:

namespace Refactoring.Day10.DesignByContract.Before
{
    public class MathMehods
    {
        public double Divide(int dividend, int divisor)
        {
            return dividend / divisor;
        }
    }
}

روش متداول «طراحي با قراردادها» جهت بهبود كيفيت كد فوق پيش از دات نت 4 به صورت زير است:

using System;

namespace Refactoring.Day10.DesignByContract.After
{
    public class MathMehods
    {
        public double Divide(int dividend, int divisor)
        {
            if (divisor == 0)
                throw new ArgumentException("divisor cannot be zero", "divisor");

            return dividend / divisor;
        }
    }
}

در اينجا پس از بررسي آرگومان divisor، قرارداد خود را به آن اعمال خواهيم كرد. همچنين در استثناي تعريف شده، پيغام واضح‌تري به همراه نام آرگومان مورد نظر، ذكر شده است كه از هر لحاظ نسبت به استثناي استاندارد و كلي DivideByZeroException مفهوم‌تر است.

در دات نت 4 ، به كمك امكانات مهياي در فضاي نام System.Diagnostics.Contracts، اين نوع بررسي‌ها نام و امكانات درخور خود را يافته‌اند:

using System.Diagnostics.Contracts;

namespace Refactoring.Day10.DesignByContract.After
{
    public class MathMehods
    {
        public double Divide(int dividend, int divisor)
        {
            Contract.Requires(divisor != 0, "divisor cannot be zero");

            return dividend / divisor;
        }
    }
}

البته اگر قطعه كد فوق را به همراه divisor=0 اجرا كنيد، هيچ پيغام خاصي را مشاهده نخواهيد كرد؛ از اين لحاظ كه نياز است تا فايل‌هاي مرتبط با آن‌را از اين آدرس دريافت و نصب كنيد. اين كتابخانه با VS2008 و VS2010 سازگار است. پس از آن، برگه‌ي Code contracts به عنوان يكي از برگه‌هاي خواص پروژه در دسترس خواهد بود و به كمك آن مي‌توان مشخص كرد كه برنامه حين رسيدن به اين نوع بررسي‌ها چه عكس العملي را بايد بروز دهد.

براي مطالعه بيشتر: