Interface فى الجافاسكربت


السلام عليكم و رحمه الله تعالى و بركاته

ال Interface هو وسيله لتحديد الوظائف التى يجب ان يمتلكها الكائن ، لكنه لا يحدد كيف تم تنفيذ هذه الوظيفه ، هذا يمكنك من استخدام كائنات مختلفه بالتبادل لأداء نفس الوظيفه مادام لهم نفس ال Interface ، لنفرض مثلا ان هناك ريموت كنترول يقوم بفتح و قفل تلفيزيون من نوع معين ، اذا قمت بتوجيه هذا الريموت كنترول لتلفيزيون لا يماثل interface -وظائف- التليفزيون الاول فإن الريموت لن يعمل مع هذا التلفيزيون ، لكن اذا كان التلفيزيونين يحتويان على نفس ال interface التى يستخدمها الريموت او كان كل تلفيزيونات العالم كلها لها نفس ال intreface الذى يستخدمه الريموت فإن هذا الريموت سيفتح و يغلق التلفيزيونات كلها و سيكون highly reusable ، و لن نحتاج الى تصميم ريموت خاص لكل تلفيزيون، انظر الى المثال البسيط التالى :

function SonyTV(){};
SonyTV.prototype={
    open:function(){/*code*/},
    close:function(){/*code*/},
    /*rest of SonyTV functions*/
}

function SonyRemote(tv){
    this.tv = tv;
};
SonyRemote.prototype = {
    open:function(){
        this.tv.close();
    },
    close:function(){
        tv.close();
    },
    tuneChannel:function(){/*code*/},
    adjustColor:function(){/*code*/},
    adjustVolume:function(){/*code*/},
    mute:function(){/*code*/},
}

يمكننا استخدام SonyRemote من SonyTV مع العلم انه ليس من شأننا كيف يتم قفل او فتح او ميزه اخرى داخل التلفيزيون Implementation ، نحن نتعامل مع اسماء الوظائف فقط Interface كما يوضح المثال البسيط التالى :

var myTV = new SonyTV();
var myRemote = new SonyRemote(myTV);
myRemote.open();
myRemote.close();

هيا بنا ننشأ كائن جديد لتلفيزيون LG مع العلم ان الكود الخاص بكيفيه تنفيذ كل وظيفه ليس من شأننا ، لأننا سوف نتعامل مع Interface كما يوضح الكود البسيط التالى :

function LGTV(){};
LGTV.prototype = {
    openTV:function(){/*code*/},
    closeTV:function(){/*code*/},
    adjustChannel:function(){/*code*/},
    tuneColors:function(){/*code*/},
    setVolume:function(){/*code*/}
}

سنختبر هل يعمل SonyRemote مع تلفيزيون LG كما يوضح الكود البسيط التالى :

var myTV = new LGTV();
var myRemote = new SonyRemote(myTV);
myRemote.open(); // Error
myRemote.close(); // Error

اسماء الوظائف التى يستخدمها تلفيزيون LG تختلف تماما عن الوظائف التى يستخدمها تلفيزيون SONY و يتعامل معها الريموت ، هذا الريموت لا يهمه كيف يتم تشغيل او اطفائه – هذا شغله مهنسدين ال hardware- لكن مايهمه انه سيجد الوظيفه المناسبه بالإسم المناسب حتى يستدعيها ، اذا نظرت للكود الخاص بالريموت ستجد ان ال constructor تبعه يقبل instance من التلفيزيون الذى سيتعامل معه .

يمكن عمل Interface بين الكائنات بمنتهى السهوله فى اللغات مثل JAVA و C# و PHP و غيرهم ، و الكود التالى يوضح كيفيه عمل Interface فى لغه PHP :

interface MyInterface {
    public function interfaceMethod($argumentOne, $argumentTwo);
}

هذا الكود يقوم بعمل Interface بإسم MyInterface ، اى class سيقوم بادراج هذا ال Interface لابد من ان يدرج الوظيفه interfaceMethod التى تقبل عبارتين argumentOne و argumentTwo ، الكود التالى يوضح كيفيه ادرج هذا ال Interface فى صنفين الاول يوافقه MyClass و التانى BadClass يخالفه :

class MyClass implements MyInterface {
    public function interfaceMethod($argumentOne, $argumentTwo){
        return $argumentOne . $argumentTwo;
    }
}

لا توجد مشكله فى هذا الصنف لأنه يدرج الوظيفه interfaceMethod التى صرح بها MyInterface ، لكن الصنف التالى BadClass ستنشأ عنه مشاكل :

class BadClass implements MyInterface {
    // No Methods
}

سينتج عن هذا الكود error فى وقت التشغيل runtime لأن المترجم يفصح اى صنف يقوم بأنه يدرج MyInterface عن طريق كتابه implements MyInterface فى تعريف الكلاس كما يوضح الكود السابق ، رساله الخطأ من الكود السابق كما يلى :

Fatal error: Class BadClass contains 1 abstract method and must therefore be declared (MyInterface::interfaceMethod)

اى صنف يقوم بادراج ال MyInterface بطريقه صحيحه ، يمكن استخدامه بالتبادل مكان الكائن الحالى الذى يدعم MyInterface .

فى جافاسكربت لا توجد خاصيه فى اللغه تقوم بعمل Intreface ولا يقوم المترجم بفحص هل الكائن صادق فى كونه يدعم هذا ال interface ام لا ، لكن لكون لغه الجافاسكربت مرنه جدا ، يمكننا تقليد عمل ال Interface و استغلال امكانياته من اجل كتابه API مرن و قابل لاعاده الاستعمال .

يمكننا تقليد عمل ال Intreface عن طريق Duck typing هذه التسميه جاءت من المقوله :

If it walks like a duck and quacks like a duck, it's a duck

يعنى لو شفت حاجه ماشيه ذى البطه و بتكاكى ذى البطه ، تبقى بطه ، هذا التكنيك يستخدم لفحص هل كائن ما مشتق من صنف ما عن طريق فحص اسماء الوظائف التى بهذا الكائن ، لكن هذا التكنيك مثالى لفحص هل كائن ما يقوم بإدراج Interface ما .

function Interface(name,methods){ // Interface function constructor
    this.name=name;
    this.methods=methods;
}

// public static method
Interface.ensureImplements = function(object,interface){
    for(var i=0, len=interface.methods.length; i<len; i++){
        var method = interface.methods[i];
        if(!object[method] || typeof object[method] != 'function'){
            throw new Error ("The Interface "+interface.name+ " method >"+ method+
            "is not implemented");
        }
    }
}

يمكننا استخدام هذا ال Interface constructor كما يلى :

var remoteInterface = new Interface("remoteInterface",['open','close']);

function GlobalRemote(tv){
Interface.ensureImplements(tv,remoteInterface);
this.tv = tv;
}
GlobalRemote.prototype= {
    open:function(){
    this.tv.open();
    },
    close:function(){
    this.tv.close();
    }
}

قمت بعمل inerface بإسم remoteInterface يحتوى على وظيفتين open و close ، و داخل ال GlobalRemote constructor قمت بفحص هل ال tv الذى يمرر لها يطابق ال remoteInterface ام لا ، لو طابق ال interface سيعمل الكود طبيعى ، اما اذا لم يطابق سيتم ارسال error يقول انه هناك وظيفه لم يتم ادراجها من هذا ال interface ، و لنفرض ان تلفيزيون LG و SONY جميعهم ادرجوا ال interface الذى بإسم globalInterface فإن الريموت سيعمل معهم جميعا ميعادا تلفيزيون Toshiba الذى لم يدرجه كما يوضح الكود التالى :

function SonyTV(){};
SonyTV.prototype = {
    open:function(){},
    close:function(){},
}

function LGTV(){};
LGTV.prototype= {
    open:function(){},
    close:function(){},
}

function ToshibaTV(){};
ToshibaTV.prototype = {
    openTV:function(){},
    closeTV:function(){},
}

var myRemote = new GlobalRemote(new SonyTV);
myRemote.open();
myRemote.close();

var myRemote = new GlobalRemote(new LGTV)
myRemote.open();
myRemote.close();

var myRemote = new GlobalRemote(new ToshibaTV);
myRemote.open(); // Error : The Interface remoteInterface 
method > open is not implemented

ال Interface مهم للغايه فى بعض ال design patterns مثل Factory و Composite و Decorator و Command ، كما انه لا بد منه عند العمل على مشاريع كبيره يشترك فيها اكثر من مبرمج حيث ستكون وسيلها التواصل بينهم هى ال Interface ، مادام هناك كائنات تدرج نفس ال Interface اذا لا يوجد مشكله من استخدام اى منها ، و اذا تطور ال api الذى تكتبه فإنه لا يوجد مشكله فى عمله على الانظمه القديمه مادام يدرج نفس ال Interface الموجود فى الانظمه القديمه ، انا قد قمت بمسح بعض الكود الخاص ب type checking فى Interface و Interface.ensureImpelemnts للتسهيل ،  يمكنك ايضا عمل وظيفه ensureImpelemnts تقبل اكثر من interface لتفحص هلى الكائن يطابقهم ام لا ، اذا كان ال interface لا يضيف قيمه للكود التى تكتبه إذا فلا تضيفه لأنه سيزيد من تعقيد الكود نسبيا و سيصعب على المبرمجين المبتدئين معرفه ماهيه ال interface ،هذا الموضوع هو الفصل الثانى من كتاب APRESS: Pro JavaScript design patterns الموجود فى العمود الجانبى فى المدونه .

الأوسمة: ,

4 تعليقات to “Interface فى الجافاسكربت”

  1. almhajer Says:

    يعتمد هذا التكنيك على النظم في انشاء تكنيك uml ومن دونه لايمكن استعيباب البرمجيات الكبيرة مع ي عالمنا العربي وانا اولهم في بر مجياتنا لانعطي اي اهتمام لهذه التقنية المستقبلية
    مستقبل لانها تلازمك في كل تطوير باختصار دون تخطيط ===دون نجاح
    بارك الله فيك وجعلها الله في ميزان حسناتك

  2. لؤى نجاتى Says:

    بالرغم انى غير متخصص فى الجافا اسكربت ولكن طريقة شرحك جيدة جداً لدرجة جعلتنى افهم هذا الموضوع بسهولة و الحمد لله

    ينبغى ان تستخدم الصور التوضيحية لكى تجعلها اكثر بساطة ايضاً

  3. smsm Says:

    WAOOOOO

  4. mytv vnpt Says:

    mytv vnpt…

    […]Interface فى الجافاسكربت « Keepondev[…]…

أضف تعليقاً

إملأ الحقول أدناه بالمعلومات المناسبة أو إضغط على إحدى الأيقونات لتسجيل الدخول:

WordPress.com Logo

أنت تعلق بإستخدام حساب WordPress.com. تسجيل خروج   / تغيير )

صورة تويتر

أنت تعلق بإستخدام حساب Twitter. تسجيل خروج   / تغيير )

Facebook photo

أنت تعلق بإستخدام حساب Facebook. تسجيل خروج   / تغيير )

Google+ photo

أنت تعلق بإستخدام حساب Google+. تسجيل خروج   / تغيير )

Connecting to %s


%d مدونون معجبون بهذه: