Farklı türlerde polimorfizm vardır, ilgilenilenlerden biri genellikle çalışma zamanı polimorfizmi / dinamik gönderisidir.
Çalışma zamanı polimorfizminin çok yüksek bir açıklaması, bir yöntem çağrısının bağımsız değişkenlerinin çalışma zamanı türüne bağlı olarak farklı şeyler yapmasıdır: nesnenin kendisi bir yöntem çağrısını çözmekle sorumludur. Bu büyük miktarda esneklik sağlar.
Bu esnekliği kullanmanın en yaygın yollarından biri bağımlılık enjeksiyonudur , örneğin farklı uygulamalar arasında geçiş yapabilir veya test için sahte nesneler enjekte edebilirim. Önceden sadece sınırlı sayıda olası seçenek olacağını biliyorum eğer onları koşullu, örneğin kodlamak için deneyebilirsiniz:
void foo() {
if (isTesting) {
... // do mock stuff
} else {
... // do normal stuff
}
}
Bu, kodun izlenmesini zorlaştırır. Alternatif, söz konusu foo-operasyon için bir arayüz sunmak ve normal bir uygulama ve o arayüzün sahte bir uygulamasını yazmak ve çalışma zamanında istenen uygulamaya "enjekte etmek" tir. “Bağımlılık enjeksiyonu” “doğru nesneyi argüman olarak geçirmek” için karmaşık bir terimdir.
Gerçek dünyadaki bir örnek olarak, şu anda bir tür makine öğrenme sorunu üzerinde çalışıyorum. Bir tahmin modeli gerektiren bir algoritmaya sahibim. Ama farklı makine öğrenme algoritmalarını denemek istiyorum. Bu yüzden bir arayüz tanımladım. Tahmin modelimden neye ihtiyacım var? Bazı girdi örnekleri, tahmin ve hataları göz önüne alındığında:
interface Model {
def predict(sample) -> (prediction: float, std: float);
}
Algoritmam bir modeli eğiten bir fabrika işlevi alır:
def my_algorithm(..., train_model: (observations) -> Model, ...) {
...
Model model = train_model(observations);
...
y, std = model.predict(x)
...
}
Şimdi model arayüzünde çeşitli uygulamalara sahibim ve bunları birbiriyle kıyaslayabilirim. Bu uygulamalardan biri aslında iki model daha alır ve bunları güçlendirilmiş bir modelde birleştirir. Bu arayüz sayesinde:
- algoritmamın belirli modelleri önceden bilmesine gerek yok,
- Modelleri kolayca değiştirebilirim ve
- Modellerimi uygulama konusunda çok esnekim var.
GUI'lerde klasik bir polimorfizm kullanım durumu vardır. Java AWT / Swing /… gibi bir GUI çerçevesinde farklı bileşenler vardır . Bileşen arabirimi / taban sınıfı, kendisini ekrana boyamak veya fare tıklamalarına tepki vermek gibi eylemleri açıklar. Birçok bileşen, alt bileşenleri yöneten kaplardır. Böyle bir konteyner kendini nasıl çizebilir?
void paint(Graphics g) {
super.paint(g);
for (Component child : this.subComponents)
child.paint(g);
}
Burada, konteynerin alt bileşenlerin kesin tiplerini önceden bilmesine gerek yoktur - Component
konteynere arayüze uyduğu sürece konteyner sadece polimorfik paint()
yöntemi çağırabilir . Bu bana AWT sınıfı hiyerarşisini keyfi yeni bileşenlerle genişletme özgürlüğü veriyor.
Yazılım geliştirme boyunca, polimorfizm teknik olarak uygulanarak çözülebilen birçok tekrarlanan problem vardır. Bu tekrar eden problem-çözüm çiftlerine tasarım desenleri denir ve bunlardan bazıları aynı isimli kitapta toplanır. Bu kitap açısından, enjekte edilen makine öğrenme modelim “bir algoritma ailesi tanımlamak, her birini kapsüllemek ve bunları değiştirilebilir yapmak” için kullandığım bir strateji olurdu . Bir bileşenin alt bileşenler içerebileceği Java-AWT örneği bir bileşik örneğidir .
Ancak her tasarımın polimorfizm kullanması gerekmez (birim testi için bağımlılık enjeksiyonunu mümkün kılmanın ötesinde, bu gerçekten iyi bir kullanım durumudur). Çoğu problem aksi halde çok durağandır. Sonuç olarak, sınıflar ve yöntemler genellikle polimorfizm için değil, basit ad alanları olarak ve güzel yöntem sözdizimi olarak kullanılır. Örneğin, birçok geliştirici account.getBalance()
büyük ölçüde eşdeğer bir işlev çağrısı gibi yöntem çağrılarını tercih eder Account_getBalance(account)
. Bu mükemmel bir yaklaşım, sadece birçok “yöntem” çağrısının polimorfizmle hiçbir ilgisi yok.