Dinamik iletimBilgisayar programlamada dinamik iletim, altyordam çağrılarının ilişkin altyordam başlangıç adresine dinamik olarak bağlanmasıdır. Bir diğer deyişle, dinamik iletim program metnindeki bir çağrı ile işletilen altyordamın programın çalışması sırasında birbirine bağlanması durumudur. Geri çağrı ve çokbiçimliliğin realize edilmesinde kullanılan bu bağlama yöntemi, yordamsal programlama dillerinde altyordam göstericileriyle gerçekleştirilirken, nesne yönelimli dillerde kalıtlama ve gerçekleştirme ilişkilerinin kullanılmasıyla otomatikman sağlanır. Altyordamların birinci sınıf dil öğesi olarak ele alındığı fonksiyonel programlama dillerinde ise, aynı işlevsellik altyordamların argüman olarak geçirilmesi ile sağlanabilir. Dinamik İletim ve Diğer KavramlarDinamik iletimin başlıca amacı, kullanıcının gereksinimlerine göre değişkenlik gösterebilecek kod parçalarının kullanıcı tarafından tamamlanmasını mümkün kılarak yazılım çerçevelerinin çokbiçimli kullanılabilmesini sağlamak ve böylece daha yüksek yeniden kullanım elde etmektir. Örnek olarak, görsel arayüzlü bir yazılımı kullanırken yaptıklarınızı düşünün, düğmelere basıyorsunuz, metin kutularını dolduruyorsunuz, listelerden seçimler yapıyorsunuz, vs. Ancak, düğmenin (ve diğer görsel öğelerin) davranışı temelde değişmediği halde, düğmeye basıldığında programın amacına dönük şeyler oluyor. Mesela, öğrenci kayıt formunun doldurulması sonrasında tıklanan Tamam düğmesi öğrenci kaydını yaparken, kitap alışverişi sitesindeki aynı görünüşlü düğmeyi tıklamanız kitapların evinize kadar gelmesini sağlayan bir sürecin başlamasına neden oluyor. Tıklamak eylemi aynıyken, olup biten değişiyor ve bunun görsel arayüz kitaplığını üreten firma tarafından bilinmesi olanaksız; resmin sizin kullandığınız yazılımı—öğrenci kayıt ve kitap alışveriş yazılımları—üretenler tarafından doldurulması gerekli. İşte bu, yordamsal programlama dillerinde altyordam göstericilerine uygun altyordamların adreslerini geçirerek sağlanırken, nesne yönelimli dillerde yazılım çerçevesince sağlanan üstsınıflardan kalıtlama veya arayüzleri gerçekleştirme ile sağlanabilir. Üstsınıftan kalıtlama veya arayüz gerçekleştirme senaryosunun geçerli olduğu durumlarda, bir nesneye gönderilen ileti sonucunda hangi metodun çağrılacağını belirleyen aşağıdaki adımların akılda tutulması yararlı olacaktır.
Programlama Dilleri ve Dinamik İletimCKabarcık sıralaması algoritmasının C programlama dilindeki soysal gerçekleştirimini içeren aşağıdaki
#ifndef KABARCIK_H
#define KABARCIK_H
typedef void* Object;
typedef int (*KARSILASTIRMA_FONK)(Object, Object);
extern void kabarcik_siralama(Object dizi[], int boy, KARSILASTIRMA_FONK kar_fonk);
#endif
Yukarıda sağlanan imzaya uygun gerçekleştirime göz atıldığında ise, işin püf noktasının fonksiyon göstericisinin kullanıldığı içteki döngünün ilk satırında olduğu görülür. Her ne kadar
#include <stdio.h>
#include "Kabarcik.h"
#define BOOL char
#define FALSE 0
#define TRUE 1
static void takas_et(Object dz[], int sol_indis, int sag_indis) {
Object gecici = dz[sol_indis];
dz[sol_indis] = dz[sag_indis];
dz[sag_indis] = gecici;
} /* void takas_et(Object[], int, int) sonu */
void kabarcik_siralama(Object dz[], int boy, KARSILASTIRMA_FONK kar) {
int gecis, j;
for(gecis = 1; gecis < boy; gecis++) {
BOOL takas_var = FALSE;
for (j = 0; j < boy - gecis; j++)
if (kar(dz[j], dz[j + 1]) > 0) {
takas_et(dz, j, j + 1);
takas_var = TRUE;
} /* if sonu */
if (!takas_var) return;
} /* for(gecis = 1; gecis < boy; gecis++) sonu */
} /* void kabarcik_siralama(Object[], int, KARSILASTIRMA_FONK) sonu */
Aşağıda sağlanan sınama programının incelenmesi olup bitenin daha iyi anlaşılmasını sağlayacaktır.
#include <stdio.h>
#include <string.h>
#include "Kabarcik.h"
typedef int* Integer;
void ksa_bas(char *ksa[], int boy) { ... }
void intleri_bas(Integer dz[], int boy) { ... }
int karakter_katar_kars(Object sol, Object sag) {
return(strcmp((char*) sol, (char *) sag));
} /* int karakter_katar_kars(Object, Object) sonu */
int int_kars(Object sol, Object sag) {
Integer ig1 = (Integer) sol;
Integer ig2 = (Integer) sag;
if (*ig1 > *ig2) return 1;
else if (*ig1 < *ig2) return -1;
else return 0;
} /* int int_kars(Object, Object) sonu */
int main(int args, char *ksa[]) {
int dizi[] = {1, 3, 102, 6, 34, 12, 35}, i;
Integer int_dz[7];
for (i = 0; i < 7; i++) int_dz[i] = &dizi[i];
printf("\nTAMSAYI DIZISI SINANIYOR\n\nSiralama oncesi\n");
intleri_bas(int_dz, 7);
kabarcik_siralama((Object*) int_dz, 7, &int_kars);
printf("\nSiralama sonrasi\n"); intleri_bas(int_dz, 7);
printf("\nKARAKTER KATARI DIZISI SINANIYOR\n\nSiralama oncesi\n");
ksa_bas(&ksa[1], args - 1);
kabarcik_siralama((Object*) &ksa[1], args - 1, karakter_katari_kars);
printf("Siralama sonrasi\n"); ksa_bas(&ksa[1], args - 1);
return(0);
} /* int main(int, char **) sonu */
C++C'nin nesne yönelimli ardılı olan C++'da dinamik iletim, fonksiyon göstericilerine ek olarak, üstsınıfta
#ifndef MEMUR_HXX
#define MEMUR_HXX
class Memur {
...
public:
virtual double aylik_gelir() = 0;
...
}; // Memur sinifinin sonu
#endif
İkinci aşamada yapılması gereken, dinamik iletimli çağrılacağı için
#ifndef GENELMUDUR_HXX
#define GENELMUDUR_HXX
#include "Memur.hxx"
class GenelMudur : public Memur { ... };
#endif
#include "GenelMudur.hxx"
...
double GenelMudur::aylik_gelir() {
// Geliri derece, kademe ve alınabilecek rüşveti hesaba katarak hesapla.
} // double GenelMudur::aylik_gelir() sonu
...
#ifndef DUZMEMUR_HXX
#define DUZMEMUR_HXX
#include "Memur.hxx"
class DuzMemur : public Memur { ... };
#endif
#include "DuzMemur.hxx"
...
double DuzMemur::aylik_gelir() {
// Geliri derece ve kademeden yararlanarak hesapla.
} // double DuzMemur::aylik_gelir() sonu
...
Dinamik iletimli fonksiyonun çokbiçimli kullanımına bir örnek aşağıdaki kod parçasından görülebilir. Dikkat edilecek olursa,
#include <vector>
using namespace std;
#include "Memur.hxx"
#include "GenelMudur.hxx"
#include "DuzMemur.hxx"
int main(void) {
vector<Memur&> memurlar;
...
double toplam_odeme = 0;
vector<Memur&>::const_iterator bas = memurlar.begin(), son = memurlar.end();
while(bas != son) {
toplam_odeme += (*bas).aylik_gelir();
bas++;
} // while (bas != son) sonu
...
} // int main(void) sonu
JavaJava'da, Kalıtlama Yoluyla Çokbiçimlilik ve Dinamik İletim
public abstract class Memur {
...
public double gelir();
...
} // Memur sınıfının sonu
public class GenelMüdür extends Memur {
...
public double gelir() {
// Geliri derece, kademe ve alınabilecek rüşveti hesaba katarak hesapla.
}
...
} // GenelMüdür sınıfının sonu
public class DüzMemur extends Memur {
...
public double gelir() {
// Geliri derece ve kademeden yararlanarak hesapla.
}
...
} // DüzMemur sınıfının sonu
Kalıtlama yoluyla çokbiçimliliğin örneklendiği aşağıdaki kod parçasından da görülebileceği gibi, gönderilen ileti sonucunda çağrılan metot, tutacağın arkasındaki nesnenin türüne göre belirlenmektedir. Buna göre,
import java.util.Vector;
public class Bordro {
Vector<Memur> çalışanlar = new Vector<Memur>();
...
double toplamÖdeme = 0;
for (Memur çalışan : çalışanlar)
toplamÖdeme += çalışan.gelir();
...
} // Bordro sınıfının sonu
Gerçekleştirme Yoluyla Çokbiçimlilik ve Dinamik İletimJava, türleri (sınıflar ve arayüzler) gibi olmak ilişkisine göre bir sıradüzenine koyan kalıtlama ilişkisinin yanı sıra sınıfları sahip oldukları ortak arayüzlere göre kategorize eden gerçekleştirme ilişkisini de sunar. Gerçekleştirme ilişkisi yoluyla dinamik iletimin kullanılması ve metotların çokbiçimli bir şekilde kullanılması, birbirleriyle benzer olsun veya olmasın, aynı kategoriye giren sınıfların ortak bir arayüzü gerçekleştirmesi ile mümkün olur.
package öğrenciişleri;
public class Öğrenci implements Comparable<Öğrenci>{
...
pubic int compareTo(Öğrenci sağ) { ... }
...
} // Öğrenci sınıfının sonu
package gelirvergisi;
public class Vatandaş implements Comparable<Vatandaş>{
...
public int compareTo(Vatandaş sağ) { ... }
...
} // Vatandaş sınıfının sonu
package algoritmalar;
import java.util.*;
public class Sıralamalar {
...
public static <V extends Comparable<? extends V>> void kabarcık(List<V> kap) {
if (kap.length <= 1) return;
boolean takasVar = false;
int geçiş = 1;
do {
takasVar = false;
for (int j = 0; j < kap.length - geçiş; j++) {
V oAnki = kap.get(j), sonraki = kap.get(j + 1);
if (oAnki.compareTo(sonraki) > 0) {
V geçici = oAnki;
oAnki = sonraki;
sonraki = geçici;
takasVar = true;
} // if (oAnki.compareTo(sonraki) > 0) sonu
} // for (int j = 0; j < kap.length - geçiş; j++) sonu
} while(++geçiş < kap.length && takasVar);
} // <V extends Comparable<V>> void kabarcık(List<V>) sonu
...
} // Sıralamalar sınıfının sonu
import gelirvergisi;
import öğrenciişleri;
import static algoritmalar.Sıralamalar;
public class AlgoritmaSınama {
...
kabarcık(öğrenciler);
...
kabarcık(vergiMükellefleri);
...
} // AlgoritmaSınama sınıfının sonu
SchemeFonksiyonel programlama dillerinden olan Scheme'de dinamik iletim, altyordamların birinci sınıf muamele görmesi nedeniyle oldukça kolay sağlanır. Altyordam türlerinin varlığı, altyordamların argüman olarak geçirilmesini ve altyordamlardan sonuç olarak döndürülmesini olanaklı kılar. Bunun sonucunda, çokbiçimli davranması beklenen altyordama değişik altyordamların geçirilmesi işimizi görecektir. Örneğin, aşağıdaki kabarcık sıralaması gerçekleştirimine ikinci argüman olarak (define (kabarcık-alg dz öncemi?)
(define (eleman-takas dz i j)
(let ([geçici (vector-ref dz i)])
(vector-set! dz i (vector-ref dz j))
(vector-set! dz j geçici)))
(define (geçiş ub)
(do ((i 0 (+ i 1)) (takas? #f))
((= i (- ub 1)) takas?)
(when (öncemi? (vector-ref dz (+ i 1)) (vector-ref dz i))
(eleman-takas dz i (+ i 1))
(set! takas? #t))))
(do ((j (vector-length dz) (- j 1))
(takas? #t (geçiş j)))
((or (not takas?) (= j 1)) dz)))
Notlar
Ayrıca bakınızDış bağlantılar
|
Portal di Ensiklopedia Dunia