پیاده سازی الگوی طراحی Modular و شی گرایی در JavaScript

دوشنبه 21 دی 1394

در این مقاله قصد داریم نحوه پیاده سازی ماژول و شی گرایی در جاوااسکریپت را آموزش دهیم .اصول شی گرایی در برنامه های تحت سرور را بسیاری از مقاله ها بحث کرده اند در این مقاله شی گرایی در سمت برنامه های سمت کاربر را بررسی می کنیم .

پیاده سازی الگوی طراحی Modular  و شی گرایی در JavaScript

به عنوان برنامه نویس باید حواستان هم به کد ها باشد و هم به طراحی برنامه تان . یعنی باید هم مسائل مربوط به سمت کاربر را مدیریت کنید و هم مسائل مربوط به سمت سرور را .

در سمت سرور برنامه هایی که وجود دارند مانند برنامه های تحت .NET و .... بیشتر برای برنامه نویسان آشنا هستند و البته زبان های سمت کلاینتی مانند جاوااسکریپت و jQuery بیشتر از سایر زبان ها مورد استفاده قرار می گیرند . اصول شی گرایی در سمت سرور را بسیاری از مقاله ها بحث کرده اند ، اصولی مانند SOLID که به صورت مختصر راجع به آن صحبت می کنیم .Solid یک کلمه مخفف است که به اختصار توضیح داده خواهد شد .

Single responsiblity principle 

هر متد یا کلاس در برنامه فقط باید یک وظیفه داشته باشد .

The open close principle

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

 Liskov Substitution Principle

کلاس هایی که از یک کلاس مشتق می شوند باید بتوانند جایگزین کلاس پایه شوند .

Interface Segregation Principle

ترجیح می دهیم اینترفیس های کوچک و تخصصی داشته باشیم تا اینکه یک اینترفیس بزرگ چند منظوره داشته باشیم .


به طور قطع این اصول و سایر اصول شی گرایی در سمت سرور را رعایت می کنیم ولی در این مقاله قصد داریم تا اصول شی گرایی در زبان های سمت کاربر را بررسی کنیم .کتابخانه های بسیاری وجود دارند که در سمت کاربر برای برنامه نویسی استفاده می شوند نمونه معروف ترین آنها Query, Backbone, Amber و AngularJS است که open source هستند.خوبی این کتابخانه ها این است که کدی که به این زبان ها نوشته می شود مثلا به زبان جاوااسکریپت نوشته می شود در اکثر جاها به یک شکل نوشته میشود و فرقی نمی کند که شما با سی شارپ کار می کنید یا PHP

به متد زیر توجه کنید که در آن یک اعتبارسنجی ساده انجام داده ایم و افرادی که سن آنها کمتر از بیست است اجازه ورود ندارند

function validateAge()   
{  
    var age = parseInt($('#age').val());  
    if (age < 20)   
    {  
        $('#error').html('Please enter a valid age');  
    }  
} 

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

به کدهای زیر توجه کنید

var Car="toyota";

 var  Car = {type: " toyota ",model:1600,color:"white"}; 

خط اول معرف یک متغیر است و خط دوم بیان می کند که car یک شی است که سه خاصیت دارد.طبعا برای دسترسی به خواص این شی هم به صورت Car.typeو یا Car.model عمل خواهیم کرد .حال که مفهوم شی را درک کردید لازم است که تعریف کلاس در جاوااسکریپت را بیاموزیم .برای تعریف یک کلاس در جاوااسکریپت از تابع استفاده میکنیم .

کلاس در ظاهر مانند تابع تعریف میشود ولی کاربرد آن متفاوت است

به کد زیر توجه کنید

function person(Name,LName,Code)

{

    this.name=Name;

    this.lname=LName;

    this.code=Code;

this.PrintRecord=function(){document.write("Name is : "+ this.name + " Last Name is : "+ LName + " Code is : "+ this.code)};

 

در هنگام ساخت یک تابع ، یک this در پشت صحنه و در حوزه تابع ساخته می شود this به شی ای که تابع را دربر گرفته است اشاره می کند مقدار this بر اساس مکانی که تابع در آن فراخوانی میشود مقداردهی میشود

 

حال که تعریف کلاس تمام شد یک شی از آن نمونه سازی می کنیم .

var Per=new person("somayeh","hatami","125656");

Per.PrintRecord();

Per.code="120000";

Per.PrintRecord();

 

پس ابتدا کلمه function را نوشته و بعد نام کلاس را می نویسیم .هر تعداد خواصی که کلاس دارد در داخل پرانتز function پارامتر قرار می دهیم. این کار را به این دلیل انجام می دهیم که در هنگام ساخت شی از کلاس بتوانیم مقداردهی کنیم .

 

در داخل کلاس هم برای مقداردهی به خاصیت ها از واژه کلیدی this استفاده می کنیم .

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


    var validationModule =   
        {  
        config:   
          {  
            ApplicationName: 'Default',  
            validationEnabled: true  
        },  
        validateAge: function(element)   
          {  
            if (this.config.validationEnabled == true)   
            {  
                return (parseInt($(element).val()) > 20);  
            } else   
            {  
                throw 'Validations are disabled';  
            }  
        }  
    };  

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

حال می توانیم از تابع اعتبارسنجی سن در هر جایی استفاده کنیم .نحوه استفاده از این تابع مانند زیر است

    var myApp= validationModule;  
    var isValidAge = myApp. validateAge($('#age'));  

هر زمانی که ما یک متغیر از نوع Var تعریف می کنیم دو مشکل وجود دارد

Global variable  و Private variable

به کد زیر توجه کنید

function getDateOfBirth()  
{  
    // private variable  
    var age = parseInt($('#age').val());  
    var dob = (new Date().getFullYear()) - age;  
    return dob;  
}

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

var config =   
{  
    user: 'Anupam'  
}  
  
function VerifyUser()  
{  
  
    if (config.user == 'Anupam')  
    {  
        var text = 'hi ' + config.user;  
    } else  
    {  
  
        // invalid user  
  
    }  
    // text has scope beyond if block   
    console.log(text);  
}  
VerifyUser();  
console.log(text); // now undefined 

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

در این جا قدری هم راجع به توابع در جاوااسکریپت صحبت می کنیم .همان طور که می دانید به توابعی که درون یک کلاس و یا شی باشند متد گفته می شود .

در جاوااسکریپت توابع به صورت زیر تعریف می شوند

function functionName(parameters) {
  code to be executed
}

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

می توان برای تعریف تابع از توابع بی نام هم استفاده کرد.

var x = function (a, b) {return a * b};
var z = x(4, 3);

با استفاده از new Function هم می توان به تعریف توابع پرداخت به نمونه زیر توجه کنید 

var myFunction = new Function("a", "b", "return a * b");
var x = myFunction(4, 3);

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

(function () {
    var x = "Hello!!";      // I will invoke myself
})();

پس اگر بعد از تعریف تابع از پرانتز باز و بسته استفاده کنیم آن تابع به صورت خودکار اجرا می شود .

در کد زیر یک ماژول به همراه سازندده تابع و اعضای خصوصی آورده شده است

    var validationModule = (function()                           
     {  
        // current scope to variable module   
        var module = this;  
      
        // private variable  
        var defaultConfig =  
        {  
            ApplicationName: 'Default',  
            validationEnabled: true  
        };  
      
        module.getConfig = defaultConfig;  
      
        module.setConfig = function(config)   
        {  
            defaultConfig.ApplicationName = config.ApplicationName;  
            defaultConfig.validationEnabled = config.validationEnabled;  
        };  
      
        module.validateAge = function(age)  
        {  
                if (defaultConfig.validationEnabled == true)  
                {  
                    return (parseInt(age) > 20);  
                } else  
                {  
                    throw 'Validations are disabled';  
                }  
            }  
            // return module  
        return module;  
    })();  

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

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

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید