Кіріспе
Бағдарламалық жасақтауда қос диспетчерлік – көптеген диспетчерліктердің ерекше түрі және шақыруға қатысқан екі нысанның орындалу кезіндегі типтеріне байланысты әртүрлі нақты функцияларға функция шақыруын жіберу механизмі. Көптеген нысанға бағытталған жүйелерде кодтағы функция шақырудан шақырылатын нақты функция бір нысанның динамикалық типіне байланысты, сондықтан олар бір реттік диспетчерлік шақырулар немесе жай ғана виртуалды функция шақырулары деп аталады. Дэн Ингаллс алғаш рет Smalltalk-та қос диспетчерлікті қалай пайдалану керектігін сипаттады, оны көптүрлі полиморфизм деп атады.
Шолу
Жалпы мәселе – хабарламаны алушыға ғана емес, сонымен қатар аргументтерге байланысты түрлі әдістерге қалай жіберу мәселесі. Осы мақсатта CLOS сияқты жүйелер көптік жөнелтуді (multiple dispatch) іске асырады. Қос жөнелту (double dispatch) – көптік жөнелтуді қолдамайтын жүйелерде полиморфизмді біртіндеп азайтатын тағы бір шешім.
Пайдалану жағдайлары
Қос жіберу есептеуді таңдау аргументтерінің орындалу уақытындағы типтеріне байланысты жағдайларда пайдалы. Мысалы, бағдарламашы қос жіберуді келесі жағдайларда қолдана алады: Объектілердің аралас жиынтығын сұрыптау: алгоритмдер объектілер тізімін белгілі бір канондық тәртіпке сұрыптауды қажет етеді. Бір элементтің екінші элементтен бұрын келетінін анықтау үшін екі типтің де және мүмкін, өрістердің бір бөлігінің де білімі қажет. Адаптивтік соқтығысу алгоритмдері әртүрлі объектілер арасындағы соқтығысуларды әртүрлі жолдармен өңдеуді қажет етеді. Мысалы, ойын ортасында ғарыш кемесі мен астероид арасындағы соқтығысу, ғарыш кемесі мен ғарыш станциясы арасындағы соқтығысудан өзгеше есептеледі. Бір-бірімен қиылысатын спрайттардың қиылысу нүктелерін әртүрлі көрсетуді қажет ететін сурет салу алгоритмдері. Персоналды басқару жүйелері әртүрлі қызметкерлерге әртүрлі жұмыс түрлерін жіберуі мүмкін. Егер есепші ретінде берілген адам объектісі мен инженерлік типте берілген жұмыс объектісі болса, кесте алгоритмі сол адамды сол жұмысқа жоспарлаудан бас тартады. Оқиғаларды өңдеу жүйелері оқиғаның типін және қабылдаушы объектінің типін дұрыс оқиғаны өңдеу процедурасын шақыру үшін пайдаланады. Құлыптар мен кілттер жүйелері, онда көптеген құлып түрлері және кілт түрлері болады, және әр кілт түрі бірнеше құлыпты ашады. Объектілердің типтерін ғана білу жеткіліксіз, сонымен қатар "бір кілттің белгілі бір құлыпты ашатынын анықтау үшін маңызды ақпараты" әртүрлі құлып түрлері үшін әртүрлі болады.
Sorting a mixed set of objects: algorithms require that a list of objects be sorted into some canonical order. Deciding if one element comes before another element requires knowledge of both types and possibly some subset of the fields. Adaptive collision algorithms usually require that collisions between different objects be handled in different ways. A typical example is in a game environment where the collision between a spaceship and an asteroid is computed differently from the collision between a spaceship and a spacestation. Painting algorithms that require the intersection points of overlapping sprites to be rendered in a different manner. Personnel management systems may dispatch different types of jobs to different personnel. A schedule algorithm that is given a person object typed as an accountant and a job object typed as engineering rejects the scheduling of that person for that job. Event handling systems that use both the event type and the type of the receptor object in order to call the correct event handling routine. Lock and key systems where there are many types of locks and many types of keys and every type of key opens multiple types of locks. Not only do you need to know the types of the objects involved, but the subset of "information about a particular key that are relevant to seeing if a particular key opens a particular lock" is different between different lock types.
Жалпы қолданылатын сөз
Жоғарыда келтірілген мысалдарда көрсетілгендей, қалыпты қолданыс – тиісті алгоритмді таңдау орындалу уақытында шақыру аргументтерінің түрлеріне сүйенуі. Сондықтан шақыру динамикалық түрде шешілуге байланысты барлық әдеттегі қосымша өнімділік шығындарына ұшырайды, бұл тек бір әдіс жіберуді қолдайтын тілге қарағанда көбінесе жоғары болады. Мысалы, C++-да динамикалық функция шақыру көбінесе бір ауытқуды есептеу арқылы шешіледі, себебі компилятор функцияның нысан әдістер кестесінде қай жерде орналасқанын біледі және ауытқуды статикалық түрде есептей алады. Екі рет жіберуді қолдайтын тілде бұл сәл қымбатқа түседі, өйткені компилятор әдістің ығысуын есептеу үшін кодты жасауы керек, соның салдарынан жалпы нұсқаулар тізбегінің ұзындығы артады (көбейетін мөлшері функцияға жасалған барлық шақырулардың санынан аспайды, бұл аса маңызды болмауы мүмкін).
C#-та қос жолдау
C#-да аргумент қабылдайтын инстанция әдісін шақырғанда, келуші үлгісін қолданбай-ақ көптеген жіберуді (multiple dispatch) іске асыруға болады. Бұл дәстүрлі полиморфизмді пайдалану және аргументті динамикалық типке түрлендіру арқылы жасалады. Орындалу уақытындағы байланыстырушы (run time binder) орындалу уақытында тиісті әдіс жүктемесін таңдайды. Бұл шешім нысанның (instance) орындалу уақытындағы типін (полиморфизм) және аргументтің орындалу уақытындағы типін ескереді.
Эйфельдегі қос диспетчерлік
Эйфель бағдарламалау тілі агенттер тұжырымын қосарланған жіберу мәселесіне қолдануға мүмкіндік береді. Төмендегі мысал агенттік тіл құрылымын қосарланған жіберу мәселесін шешу үшін пайдаланады. Әртүрлі пішіндегі НЫСАН мен оларға НЫСАН салуға болатын СҮРЕТ салу беті бар проблемалық доменді қарастырайық. НЫСАН мен СҮРЕТ екеуі де өздерінде "draw" деп аталатын функцияны біледі, бірақ бір-бірінде емес. Біз екі типтегі нысандардың келуші үлгісін қолдана отырып, қосарланған жіберу арқылы бір-бірімен үйлесімді түрде өзара әрекеттесуін қамтамасыз етуді қалаймыз. Міндет – полиморфты СҮРЕТтің өзіне полиморфты НЫСАН салуын іске асыруда.
Құрылғы
SHAPE немесе SURFACE-ке қарамас бұрын, екі рет жіберудің жоғары деңгейдегі байланыссыз қолданылуын қарастыруымыз қажет.
Эйфель мысалынан қорытынды
Екі есе жіберуге қатысты айтсақ, Эйфель дизайнер мен бағдарламашыға сыныптық процедураларды олардың сыныптарынан ажырату арқылы, оларды агенттерге айналдырып, тікелей объектілік білім деңгейін одан әрі азайтуға мүмкіндік береді. Агенттерде де нақты қолтаңбалар мен мүмкін болатын нәтижелер (сұраулар үшін) болады, бұл оларды нақты объектінің егжей-тегжейін бермей, статикалық типті тексеруге қолайлы құралдарға айналдырады. Агенттер толық полиморфты, сондықтан нәтижедегі код тек қана жергілікті жұмысты орындау үшін қажетті білімге ие болады. Әйтпесе, көптеген ковариантты объектілер арасында тараған нақты ішкі сыныптық ерекшеліктерге қатысты білімнің болуынан техникалық қолдау жүктемесі арта қоймайды. Агенттерді қолдану мен олардың жұмыс істеу механизмі осыны қамтамасыз етеді. Агенттерді пайдаланудың бір кемшілігі – агенттің есептеу тұрғысынан тікелей шақырудан қымбат болуы мүмкін. Осыны ескере отырып, екі есе жіберуде және келуші үлгілерінде агенттерді қолдануға асығуға болмайды. Егер ковариантты өзара әрекеттесуге қатысатын сынып түрлерінің шегі анық болса, онда есептеу шығыны жағынан тікелей шақыру тиімдірек шешім болады. Дегенмен, қатысушы типтердің сыныптық доменінің өсуі немесе айтарлықтай өзгеруі күтілсе, агенттер екі есе жіберу үлгісінде техникалық қолдау жүктемесін азайтуға тамаша мүмкіндік береді.