OOP - nedir bu? Nesneye yönelik programlamanın temel ilkeleri. OOP nedir ve ne ile kullanılır? Nesneye Yönelik Programlamada Veri Türleri

  • 30.11.2023

Nesne yönelimli dillerde nasıl programlanacağını bilmiyorum. Öğrenmedim. Java'da 5 yıllık endüstriyel programlamadan sonra, nesne yönelimli tarzda iyi bir sistemin nasıl oluşturulacağını hala bilmiyorum. Sadece anlamıyorum.

Dürüstçe öğrenmeye çalıştım. Desenleri inceledim, açık kaynaklı projelerin kodlarını okudum, kafamda tutarlı kavramlar oluşturmaya çalıştım ama yine de yüksek kaliteli nesne yönelimli programlar oluşturmanın ilkelerini anlamadım. Belki başkası onları anladı ama ben anlayamadım.

Ve işte kafamı karıştıran birkaç şey.

OOP'nin ne olduğunu bilmiyorum

Cidden. OOP'un ana fikirlerini formüle etmek benim için zor. İşlevsel programlamada ana fikirlerden biri vatansızlıktır. Yapısal olarak - ayrışma. Modülerde işlevsellik tam bloklara bölünmüştür. Bu paradigmaların herhangi birinde, baskın ilkeler kodun %95'ine uygulanır ve dil, bunların kullanımını teşvik edecek şekilde tasarlanmıştır. OOP için böyle bir kural bilmiyorum.
  • Soyutlama
  • Kapsülleme
  • Miras
  • Polimorfizm
Bir dizi kurala benziyor değil mi? Peki vakaların %95'inde uyulması gereken kurallar bunlar mı? Hımm, daha yakından bakalım.

Soyutlama

Soyutlama güçlü bir programlama aracıdır. Büyük sistemler kurmamıza ve bunlar üzerinde kontrol sahibi olmamıza olanak tanıyan şey budur. Eğer böyle bir araçla silahlanmış olmasaydık, bugünkü program düzeyine yaklaşmamız pek mümkün değildi. Ancak soyutlamanın OOP ile ilişkisi nedir?

İlk olarak, soyutlama yalnızca OOP'nin veya genel olarak programlamanın bir özelliği değildir. Soyutlama düzeyleri yaratma süreci, insan bilgisinin hemen hemen tüm alanlarına uzanır. Böylece malzemelerin moleküler yapılarının detaylarına girmeden, onlar hakkında yargılarda bulunabiliyoruz. Veya yapıldıkları malzemelerden bahsetmeden nesneler hakkında konuşun. Veya bir bilgisayar, bir uçak türbini veya insan vücudu gibi karmaşık mekanizmalardan, bu varlıkların bireysel ayrıntılarını hatırlamadan bahsedin.

İkincisi, tarihteki ilk programcı olarak kabul edilen Ada Lovelace'in yazılarından başlayarak programlamada her zaman soyutlamalar olmuştur. O zamandan bu yana insanlar programlarında sürekli olarak soyutlamalar oluşturdular ve çoğunlukla bunun için yalnızca en basit araçları kullandılar. Bu nedenle, Abelson ve Sussman, ünlü kitaplarında, karmaşık sayıları ve hatta polinomları destekleyen denklemleri çözmek için yalnızca prosedürleri ve bağlantılı listeleri kullanarak bir sistemin nasıl oluşturulacağını anlatıyorlar. Peki OOP hangi ek soyutlama araçlarını sağlıyor? Hiçbir fikrim yok. Kodu alt programlara mı ayırıyorsunuz? Herhangi bir üst düzey dil bunu yapabilir. Rutinleri tek bir yerde mi birleştiriyorsunuz? Bunun için yeterli modül var. Tiplendirme mi? FKÖ'den çok önce de vardı. Denklem çözme sistemi örneği, soyutlama seviyelerinin oluşturulmasının dil araçlarına değil, programcının yeteneklerine bağlı olduğunu açıkça göstermektedir.

Kapsülleme

Kapsüllemenin temel avantajı uygulamayı gizlemektir. İstemci kodu yalnızca arayüzü görür ve yalnızca ona güvenebilir. Bu, uygulamayı değiştirmeye karar verebilecek geliştiricilere zaman tanır. Ve bu gerçekten harika. Ama yine soru şu: OOP'un bununla ne ilgisi var? Tüm Yukarıdaki paradigmalar uygulamanın gizlenmesini içerir. C'de programlama yaparken arayüzü başlık dosyalarına ayırırsınız, Oberon alanları ve yöntemleri modülde yerel hale getirmenize olanak tanır ve son olarak birçok dilde soyutlama, uygulamayı da kapsayan alt rutinler aracılığıyla basit bir şekilde oluşturulur. Üstelik nesne yönelimli dillerin kendisi de sıklıkla kapsülleme kuralını ihlal etmek, Java'daki alıcılar ve ayarlayıcılar, C#'taki özellikler vb. gibi özel yöntemlerle verilere erişim sağlar. (Yorumlarda programlama dillerindeki bazı nesnelerin OOP açısından nesne olmadığını öğrendik: veri aktarım nesneleri yalnızca veri aktarımından sorumludur ve bu nedenle tam teşekküllü OOP varlıkları değildir ve bu nedenle kapsüllemeyi korumaları gerekir. Öte yandan, mimari esnekliği korumak için erişimci yöntemleri en iyi şekilde korunur. Bu şekilde karmaşıklaşır.) Üstelik Python gibi bazı nesne yönelimli diller hiçbir şeyi gizlemeye çalışmaz. ancak yalnızca kodu kullanan geliştiricilerin zekasına güvenin.

Miras

Kalıtım, OOP sayesinde gerçekten sahneye çıkan birkaç yeni şeyden biridir. Hayır, nesne yönelimli diller yeni bir fikir yaratmadı - kalıtım başka herhangi bir paradigmada uygulanabilir - ancak OOP ilk kez bu kavramı dilin düzeyine getirdi. Mirasın avantajları da açıktır: neredeyse Bir sınıftan memnunsanız, bir alt öğe oluşturabilir ve onun işlevselliğinin bir kısmını geçersiz kılabilirsiniz. C++ veya Scala gibi çoklu kalıtımı destekleyen dillerde (ikincisinde özellikler yoluyla), başka bir kullanım durumu ortaya çıkar - karışımlar, kodu kopyalamadan işlevselliği yeni bir sınıfa "karıştırmanıza" olanak tanıyan küçük sınıflar.

Peki OOP'u bir paradigma olarak diğerlerinden ayıran şey bu mu? Hmm... eğer öyleyse, neden onu gerçek kodda bu kadar nadiren kullanıyoruz? Kodun %95'inin baskın paradigmanın kurallarına uyduğu konusunda söylediklerimi hatırlıyor musunuz? Şaka yapmıyordum. İşlevsel programlamada kodun en az %95'i değişmez verileri ve yan etkileri olmayan işlevleri kullanır. Modülerde neredeyse tüm kodlar mantıksal olarak modüller halinde paketlenir. Yapısal programlamanın savunucuları, Dijkstra'nın ilkelerini takip ederek programın tüm bölümlerini küçük parçalara ayırmaya çalışırlar. Kalıtım çok daha az sıklıkla kullanılır. Belki kodun %10'unda, belki %50'sinde, bazı durumlarda (örneğin, çerçeve sınıflarından miras alırken) - %70'inde, ama daha fazla değil. Çünkü çoğu durumda bu kolaydır gerek yok.

Üstelik miras tehlikeli iyi tasarım için. O kadar tehlikeli ki Dörtlü Çete (görünüşe göre FKÖ'nün vaizleri) kitaplarında mümkün olduğunda bunun delegasyonla değiştirilmesini tavsiye ediyor. Şu anda popüler olan dillerde var olan kalıtım, kırılgan tasarıma yol açmaktadır. Bir atadan miras alınan bir sınıf artık diğerlerinden miras alınamaz. Atayı değiştirmek de tehlikeli hale gelir. Elbette özel/korumalı değiştiriciler vardır, ancak bunlar aynı zamanda sınıfın nasıl değişebileceğini ve müşteri kodunun onu nasıl kullanabileceğini tahmin etmek için önemli psişik yeteneklere de ihtiyaç duyar. Kalıtım o kadar tehlikeli ve kullanışsız ki, büyük çerçeveler (Java'daki Spring ve EJB gibi) onu nesne yönelimli olmayan diğer araçlar (örneğin metaprogramming) lehine terk ediyor. Sonuçlar o kadar öngörülemez ki, bazı kütüphaneler (Guava gibi) sınıflarına kalıtımı yasaklayan değiştiriciler atadılar ve yeni Go dilinde miras hiyerarşisini tamamen terk etmeye karar verildi.

Polimorfizm

Belki de çok biçimlilik nesne yönelimli programlamanın en iyi yanıdır. Polimorfizm sayesinde, çıktı sırasında Person tipindeki bir nesne “Shandorkin Adam Impolitovich”e, Point tipindeki bir nesne ise “” gibi görünür. “Mat1 * Mat2” yazmanıza ve sıradan sayıların çarpımına benzer şekilde matrislerin çarpımını almanıza olanak sağlayan da budur. Bu olmasaydı, verinin ağdan mı, bir dosyadan mı, yoksa bellekteki bir satırdan mı geldiğine bakılmaksızın giriş akışından veri okumak mümkün olmazdı. Arayüzlerin olduğu her yerde polimorfizm de ima edilir.

Polimorfizmi gerçekten seviyorum. Bu nedenle ana dillerdeki sorunlarından bahsetmeyeceğim bile. Sevk yaklaşımının sadece tür bazında darlığı ve bunun nasıl yapılabileceği konusunda da sessiz kalacağım. Çoğu durumda olması gerektiği gibi çalışır ve bu da kötü değildir. Soru şu: polimorfizm OOP'yi diğer paradigmalardan ayıran ilkenin ta kendisi midir? Eğer bana sormuş olsaydınız (ve bu metni okuduğunuza göre, sorduğunuzu varsayabilirsiniz), "hayır" cevabını verirdim. Bunun nedeni ise koddaki kullanım yüzdesinin hala aynı olmasıdır. Belki arayüzler ve polimorfik yöntemler kalıtımdan biraz daha yaygındır. Ancak işgal ettikleri kod satırı sayısını, olağan prosedür tarzında yazılan satır sayısıyla karşılaştırın; ikincisinden her zaman daha fazlası vardır. Bu tarz programlamayı teşvik eden dillere baktığımda onlara polimorfik demiyorum. Çok biçimliliği destekleyen diller - evet bu normaldir. Ancak polimorfik diller değil.

(Ancak bu benim görüşüm. Her zaman katılmayabilirsiniz.)

Yani soyutlama, kapsülleme, kalıtım ve polimorfizm - bunların hepsi OOP'tadır, ancak bunların hiçbiri onun ayrılmaz bir özelliği değildir. Peki OOP nedir? Nesne yönelimli programlamanın özünün nesnelerde (oldukça mantıklı geliyor) ve sınıflarda yattığına dair bir görüş var. Kod ve veriyi birleştirme fikri ve bir programdaki nesnelerin gerçek dünyadaki varlıkları yansıtması fikridir. Bu görüşe daha sonra döneceğiz ama önce bazı i'leri noktalayalım.

Kimin OOP'si daha serin?

Önceki bölümden, programlama dillerinin nesne yönelimli programlamayı uygulama biçimleri açısından büyük ölçüde farklılık gösterebileceği açıktır. Tüm dillerdeki tüm OOP uygulamalarının toplamını alırsanız, büyük olasılıkla hepsinde ortak olan tek bir özellik bulamazsınız. Bu hayvanat bahçesini bir şekilde sınırlamak ve mantığını netleştirmek için yalnızca tek bir gruba odaklanacağım; tamamen nesne yönelimli diller, yani Java ve C#. Bu durumda "tamamen nesne yönelimli" terimi, dilin diğer paradigmaları desteklemediği veya bunları aynı OOP aracılığıyla uygulamadığı anlamına gelir. Örneğin Python veya Ruby saf olmayacak çünkü tek bir sınıf bildirimi olmadan üzerlerine kolayca tam teşekküllü bir program yazabilirsiniz.

Java ve C#'ta OOP'un özünü daha iyi anlamak için bu paradigmanın diğer dillerdeki uygulama örneklerine bakalım.

Küçük konuşma. Modern benzerlerinden farklı olarak bu dil, dinamik olarak yazılmıştı ve OOP'yi uygulamak için bir mesaj aktarma stili kullanıyordu. Nesneler yöntemleri çağırmak yerine birbirlerine mesaj gönderiyordu ve eğer alıcı gelenleri işleyemezse mesajı başka birine iletiyordu.

Ortak Lisp. Başlangıçta CL aynı paradigmayı izledi. Daha sonra geliştiriciler `(send obj "some-message)" yazmanın çok uzun olduğuna karar verdiler ve notasyonu bir yöntem çağrısına - `(some-method obj)' dönüştürdüler. Bugün, Common Lisp olgun bir nesne yönelimli programlama sistemine sahiptir ( CLOS) çoklu kalıtım, çoklu yöntemler ve metasınıf desteğiyle. Ayırt edici bir özellik, CL'deki OOP'nin nesneler etrafında değil, genel işlevler etrafında dönmesidir.

Clojure. Clojure'un iki nesne yönelimli programlama sistemi vardır - biri Java'dan miras alınmıştır, ikincisi ise çoklu yöntemlere dayalıdır ve daha çok CLOS'a benzer.

R.İstatistiksel veri analizine yönelik bu dil ayrıca 2 nesne yönelimli programlama sistemine sahiptir - S3 ve S4. Her ikisi de S dilinden miras alınmıştır (R'nin ticari S'nin açık kaynaklı bir uygulaması olduğu göz önüne alındığında bu şaşırtıcı değildir). S4, modern ana dillerdeki OOP uygulamalarıyla büyük ölçüde eşleşir. S3, dilin kendisi kullanılarak basit bir şekilde uygulanan daha hafif bir seçenektir: alınan nesnenin "sınıf" niteliğine dayalı olarak istekleri gönderen genel bir işlev oluşturulur.

JavaScript. Farklı bir sözdizimi kullanmasına rağmen ideolojik olarak Smalltalk'a benzer. Kalıtım yerine prototip oluşturmayı kullanır: İstenilen özellik veya çağrılan yöntem nesnenin kendisinde değilse, istek prototip nesnesine (tüm JavaScript nesnelerinin prototip özelliği) iletilir. İlginç bir gerçek şu ki, tüm sınıf nesnelerinin davranışı, prototip yöntemlerinden birinin değiştirilmesiyle değiştirilebilir (örneğin, dize sınıfı için `.toBASE64` yönteminin eklenmesi çok hoş görünüyor).

Python. Genel olarak ana dillerle aynı konsepti izler, ancak aynı zamanda öznitelik aramasının JavaScript veya Smalltalk'ta olduğu gibi başka bir nesneye aktarılmasını da destekler.

Haskell. Haskell'de hiçbir durum yoktur ve dolayısıyla alışılmış anlamda hiçbir nesne yoktur. Ancak burada hala bir tür OOP vardır: veri türleri bir veya daha fazla tür sınıfına ait olabilir. Örneğin, Haskell'deki hemen hemen tüm türler Eq sınıfındadır (2 nesne arasındaki karşılaştırma işlemlerinden sorumludur) ve tüm sayılar ayrıca Num (sayılar üzerinde işlemler) ve Ord (sayılar üzerinde işlemler) sınıflarındadır.<, <=, >=, >). Adet dillerinde türler sınıflara (verilerin) ve tür sınıfları da arayüzlere karşılık gelir.

Devletli mi, Vatansız mı?

Ancak daha yaygın olan nesne yönelimli programlama sistemlerine dönelim. Hiçbir zaman anlayamadığım şey, nesnelerin içsel durumla olan ilişkisidir. OOP'yi incelemeden önce her şey basit ve şeffaftı: birbiriyle ilişkili birkaç veriyi depolayan yapılar var, bunları işleyen prosedürler (işlevler) var. yürümek (köpek), para çekmek (hesap, miktar). Sonra nesneler geldi ve bu da sorun değildi (programları okumak çok daha zor olmasına rağmen - köpeğim yürüyordu [kim?] ve hesap para çekiyordu [nereden?]). Daha sonra veri gizlemeyi öğrendim. Köpeği hâlâ gezdirebiliyordum ama artık yemeğinin bileşimine bakamıyordum. Yiyeceklerin hiçbir faydası olmadı (muhtemelen food.eat(dog) yazabilirsiniz ama ben yine de köpeğimin yemek yemesini tercih ediyorum). Yiyecek yalnızca veridir ve benim (ve köpeğimin) yalnızca ona erişmemiz gerekiyordu. Tüm Sadece. Ancak 90'ların sonlarındaki eski kot pantolonlarda olduğu gibi paradigmanın çerçevesine uymak artık mümkün değildi.

Tamam, veri erişim yöntemlerimiz var. Hadi bu küçük kendimizi kandıralım ve verilerimizin gerçekten gizli olduğunu varsayalım. Ama artık nesnelerin her şeyden önce veri, sonra da belki onları işleyen yöntemler olduğunu biliyorum. Programların nasıl yazılacağını, tasarlarken nelere dikkat edilmesi gerektiğini anladım.

Aydınlanmanın tadını çıkaracak zamanım olmadan, internette vatansız kelimesini gördüm (yemin ederim ki etrafı bir ışıltıyla çevriliydi ve t ve l harflerinin üzerinde bir hale asılıydı). Literatürün kısa bir incelemesi, nesne tutarlılığını izlemeye gerek kalmadan şeffaf kontrol akışının ve basit çoklu iş parçacığının harika dünyasını ortaya çıkardı. Elbette hemen bu harika dünyaya dokunmak istedim. Ancak bu, herhangi bir kuralın tamamen reddedilmesi anlamına geliyordu - artık köpeğin kendi başına mı yürümesi gerektiği veya bunun için özel bir Yürüyüş Yöneticisinin gerekli olup olmadığı açık değildi; Bir hesaba ihtiyacınız var mı, yoksa tüm işi Banka mı halledecek ve öyleyse parayı statik mi yoksa dinamik olarak mı yazacak, vb. Kullanım durumlarının sayısı katlanarak arttı ve gelecekteki tüm kullanım durumları, büyük bir yeniden düzenleme ihtiyacına yol açabilir.

Bir nesnenin ne zaman durumsuz hale getirilmesi gerektiğini, ne zaman durum bilgisi olması gerektiğini ve ne zaman yalnızca bir veri taşıyıcısı olması gerektiğini hâlâ bilmiyorum. Bazen barizdir ama çoğu zaman değildir.

Yazma: statik mi yoksa dinamik mi?

C# ve Java gibi diller hakkında karar veremediğim bir diğer konu da bunların statik olarak mı yoksa dinamik olarak mı yazıldığıdır. Çoğu insan muhtemelen şöyle haykıracaktır: “Ne saçmalık! Elbette statik olarak yazılmış! Türler derleme zamanında kontrol edilir! Ama gerçekten bu kadar basit mi? Bir programcının, bir yöntemin parametrelerinde X tipini belirterek, ona her zaman X tipi nesnelerin aktarılacağından emin olabileceği doğru mu? Bu doğru, olamaz, çünkü... X tipi bir parametreyi X yöntemine geçirmek mümkün olacak veya onun varisi. Öyle görünüyor, ne olmuş yani? X sınıfının torunları yine X ile aynı yöntemlere sahip olacaktır. Yöntemler yöntemdir ancak işin mantığı tamamen farklı çıkabilir. En yaygın durum, bir alt sınıfın X dışındaki ihtiyaçlar için optimize edildiği ortaya çıkmasıdır ve yöntemimiz tam olarak bu optimizasyona güvenebilir (böyle bir senaryo size gerçekçi gelmiyorsa, bazı gelişmiş açık kaynak kitaplıkları için bir eklenti yazmayı deneyin - veya kütüphanenin mimarisini ve algoritmalarını analiz etmek için birkaç hafta harcayacaksınız veya uygun imzalı yöntemleri rastgele çağıracaksınız). Sonuç olarak program çalışır, ancak işlem hızı büyük ölçüde düşer. Her ne kadar derleyicinin bakış açısından her şey doğru olsa da. Java'nın halefi olarak adlandırılan Scala'nın birçok yerde varsayılan olarak yalnızca belirtilen türdeki argümanların iletilmesine izin vermesi, ancak bu davranışın değiştirilebilmesi önemlidir.

Diğer bir sorun ise Java'daki hemen hemen her nesnenin ve C#'taki herhangi bir Nullable nesnenin yerine geçirilebilen null değeridir. null aynı anda tüm türlere aittir ve aynı zamanda hiçbirine ait değildir. null'un ne alanları ne de yöntemleri vardır, dolayısıyla ona yapılan herhangi bir çağrı (null kontrolü dışında) hatayla sonuçlanır. Görünüşe göre herkes buna alışkın, ancak karşılaştırma yapmak için Haskell (ve aynı Scala), diğer dillerde null döndürebilecek işlevleri sarmak için özel türler (Belki Haskell'de, Option Scala'da) kullanmak zorunda kalıyor. Sonuç olarak, Haskell hakkında sık sık "bir program derlemek zordur, ancak başarılı olursanız büyük olasılıkla doğru şekilde çalışır" derler.

Öte yandan, ana akım diller açıkça dinamik olarak yazılmamıştır ve bu nedenle basit arayüzler ve esnek prosedürler gibi özelliklere sahip değildir. Sonuç olarak Python veya Lisp tarzında yazmak da imkansız hale geliyor.

Zaten tüm kurallar biliniyorsa, bu tiplemeye ne ad verildiğinin ne önemi var? Aradaki fark mimari tasarıma hangi taraftan yaklaştığınızdır. Bir sistemin nasıl oluşturulacağı konusunda uzun süredir devam eden bir tartışma var: Çok tür ve az işlev mi, yoksa az tür ve çok işlev mi? İlk yaklaşım Haskell'de, ikincisi ise Lisp'te aktif olarak kullanılmaktadır. Modern nesne yönelimli diller arada bir şey kullanır. Bunun kötü olduğunu söylemek istemiyorum - muhtemelen avantajları vardır (sonuçta, Java ve C#'ın çok dilli platformlar olduğunu unutmamalıyız), ancak her yeni projeye başladığımda nereden başlayacağımı merak ediyorum. tasarım - türlerle veya işlevsellikten.

Ve ilerisi...

Sorunu nasıl modelleyeceğimi bilmiyorum. OOP'un gerçek dünya nesnelerini bir programda görüntülemenize izin verdiğine inanılmaktadır. Ancak gerçekte bir köpeğim (iki kulağı, dört patisi ve bir tasması olan) ve bir banka hesabım (yönetici, katipler ve öğle yemeği molası var) ve programda - WalkManager, AccountFactory... fikir. Ve mesele, programın gerçek dünyadaki nesneleri yansıtmayan yardımcı sınıflara sahip olması değil. Gerçek şu ki akış değişikliklerini kontrol etme. Walking Manager beni köpeğimi gezdirme zevkinden mahrum ediyor ve ben de ruhsuz bir Banka Hesabından para alıyorum (hey, geçen hafta para bozdurduğum o sevimli kız nerede?).

Belki bir züppeyim ama bilgisayardaki veriler, köpeğimi veya bir banka hesabımı tanımlasa bile sadece veri olduğunda çok daha mutluydum. Gerçek dünyaya bakılmaksızın verilerle uygun olanı yapabilirdim.

Ayrıca işlevselliği nasıl düzgün bir şekilde ayrıştıracağımı da bilmiyorum. Python veya C++'da, bir dizeyi sayıya dönüştürmek için küçük bir işleve ihtiyacım olursa, bunu dosyanın sonuna yazdım. Java veya C#'ta onu ayrı bir StringUtils sınıfına koymak zorunda kalıyorum. OO öncesi dillerde, bir işlevden iki değeri (çekilen tutar ve hesap bakiyesi) döndürmek için özel bir sarmalayıcı bildirebilirdim. OOP dillerinde tam teşekküllü bir İşlem Sonucu sınıfı oluşturmam gerekecek. Ve projeye yeni katılan bir kişiye (hatta bir hafta sonra bana) bu ders, sistemin mimarisinde de aynı derecede önemli ve temel görünecektir. 150 dosya ve hepsi eşit derecede önemli ve temel - ah evet, şeffaf mimari, harika soyutlama seviyeleri.

Etkili programların nasıl yazılacağını bilmiyorum. Verimli programlar çok az bellek kullanır; aksi takdirde çöp toplayıcı yürütmeyi sürekli yavaşlatır. Ancak nesne yönelimli dillerde en basit işlemi gerçekleştirmek için bir düzine nesne oluşturmanız gerekir. Bir HTTP isteği yapmak için, URL türünde bir nesne, ardından HttpConnection türünde bir nesne, ardından İstek türünde bir nesne oluşturmam gerekiyor... peki, fikri anladınız. Prosedürel programlamada, birkaç prosedürü basitçe çağırır ve onlara yığın üzerinde oluşturulan bir yapıyı aktarırdım. Büyük olasılıkla, sonucu depolamak için bellekte yalnızca bir nesne oluşturulacaktır. OOP'ta her zaman hafızayı karıştırmam gerekiyor.

Belki de OOP gerçekten güzel ve zarif bir paradigmadır. Belki de bunu anlayacak kadar akıllı değilim. Muhtemelen nesne yönelimli bir dilde gerçekten güzel bir program yaratabilecek biri vardır. Onları ancak kıskanabilirim.

Deneyimlerime dayanarak, her zaman OOP'yi, bunda neyin yanlış olduğunu - polimorfizm, kapsülleme ve kalıtım - anladığımı düşündüğümü söyleyebilirim, ancak iş bu noktaya geldiğinde biraz zor oldu. Gelecekte kimsenin tırmığıma basmaması için her şeyi düzene koymak istiyorum :)

Aşama 1.

Küçük bir teori:

Nesne yönelimli programlama(bundan sonra OOP olarak anılacaktır), ana kavramların nesne ve sınıf kavramları olduğu bir programlama paradigmasıdır.

OOP'un merkezinde nesne kavramı yer almaktadır.

Bir obje mesajların gönderilebildiği ve verilerini kullanarak onlara yanıt verebilen bir varlıktır, bir sınıfın örneğidir. Nesnenin verileri programın geri kalanından gizlenir. Verileri gizlemeye kapsülleme denir.

Kapsüllemenin varlığı, bir programlama dilinin nesnelliği için yeterlidir, ancak henüz nesne yönelimli olduğu anlamına gelmez; bu, mirasın varlığını gerektirir.

Ancak kapsülleme ve kalıtımın varlığı bile bir programlama dilini OOP açısından tamamen nesne tabanlı yapmaz. OOP'un temel avantajları yalnızca programlama dilinde polimorfizm uygulandığında, yani aynı spesifikasyona sahip nesnelerin farklı uygulamalara sahip olma yeteneğinde ortaya çıkar.

OOP'ta başka bir önemli özelliğin - soyutlamanın vurgulanmaya değer olduğu fikrine sıklıkla rastladığımı vurgulamak isterim. Resmi olarak OOP'nin zorunlu özellikleri arasında yer almıyordu, ancak silinmemesi gerekiyor.

Soyutlama- bu, bir nesnenin bir dizi önemli özelliğini vurgulamanın, önemli olmayanları değerlendirme dışı bırakmanın bir yoludur.Buna göre soyutlama, bu tür tüm özelliklerin bir kümesidir.

Kapsülleme onlarla çalışan veri ve yöntemleri bir sınıfta birleştirmenize ve uygulama ayrıntılarını kullanıcıdan gizlemenize olanak tanıyan bir sistem özelliğidir.

Miras- bu, kısmen veya tamamen ödünç alınmış işlevselliğe sahip mevcut sınıfa dayalı yeni bir sınıfı tanımlamanıza olanak tanıyan sistemin bir özelliğidir. Kalıtımın türetildiği sınıfa temel, ebeveyn veya üst sınıf denir. Yeni sınıf - soyundan gelen, mirasçı veya türetilmiş sınıf

Polimorfizm- bu, nesnenin türü ve iç yapısı hakkında bilgi olmadan aynı arayüze sahip nesneleri kullanma sisteminin özelliğidir.

Adım 2.

Kapsülleme.

Kapsülleme, uygulama ayrıntılarını gizlemenize ve yalnızca sonraki kullanım için gerekli olanı ortaya çıkarmanıza olanak tanır. Başka bir deyişle kapsülleme bir erişim kontrol mekanizmasıdır.

Bu neden gerekli?

Sanırım kimsenin kütüphanede yazdığınız hiçbir şeyi değiştirmesini istemezsiniz.

Ve eğer bu deneyimli bir programcıysa, o zaman bu yine de affedilebilir, ancak yine de hoş değil, ancak bu, kodu hafif bir el ile ve hatta yanlış bozkırda bile değiştirmeye karar veren yeni başlayan veya dikkatsiz bir kişi ise, yapmayız bunu istemiyorum! Kendinizi bu tür eylemlerden korumak için kapsülleme vardır.

Kapsüllemenin Amacı– sınıfın dış arayüzünün (diğer sınıfların kullanabileceği) uygulamaya bağımlılığından kurtulun. Öyle ki, sınıftaki en ufak bir değişiklik, sınıfın dış davranışında bir değişikliğe yol açmaz. Nasıl kullanılacağına bakalım.

4 tür erişim değiştirici vardır:halk, korumalı, özel Ve varsayılan.

Halk – seviye, herhangi bir sınıfın ve herhangi bir paketin örneğinden bu değiştiriciye sahip bir bileşene erişimi varsayar.

Korumalı – düzey, hangi pakette olduklarına bakılmaksızın, yerel sınıf ve alt sınıfların örneklerinden bu değiştiriciye sahip bir bileşene erişimi varsayar.

Varsayılan – seviye, bu sınıfla aynı pakette bulunan herhangi bir sınıfın örneklerinden bu değiştiriciye sahip bir bileşene erişimi varsayar.

Özel – seviye, bu değiştiriciye sahip bir bileşene yalnızca bu sınıftan erişim sağladığını varsayar.

Genel sınıf İnsan ( genel Dize adı; korumalı Dize soyadı; özel int yaş; int doğum günüYıl; )

genel Dize adı; - uygulamanın herhangi bir yerinden erişilebilen bir ad.
korumalı Dize soyadı; - yerli sınıftan ve soyundan gelen soyadı.
özel int yaş; - yaş yalnızca İnsan sınıfında mevcuttur.
int doğum günüYıl; - açık bir erişim değiştiricisi belirtilmemiş olsa da, sistem bunu varsayılan olarak algılar, doğum yılı, Human sınıfının bulunduğu paketin tamamı için geçerli olacaktır.

Bir sınıfın farklı yapısal öğeleri için yalnızca belirli düzeylerde erişim değiştiricileri uygulamak mümkündür.

Bir sınıf için - yalnızca genel ve varsayılan.

Sınıf nitelikleri için - 4 türün tümü.

Tasarımcılar için - 4 türün tümü.

Yöntemler için - 4 türün tümü.

Aşama 3.

Miras.

Miras bir nesnenin diğerinin özelliklerini kazanma sürecidir. Daha doğrusu, bir nesne başka bir nesnenin temel özelliklerini miras alabilir ve bunlara yalnızca kendisine özgü özellikler ekleyebilir.

Kalıtım önemlidir çünkü hiyerarşik sınıflandırma kavramını desteklememize olanak tanır. Sınıf hiyerarşisinin kullanılması büyük bilgi akışlarının yönetilebilir olmasını sağlar.

Klasik bir örnek kullanarak bu mekanizmaya bakalım: Geometrik şekiller.

Şekil arayüzümüz var:

Genel arayüz Şekil ( public void çizimi (); public void delete (); public void move (); public String getColor (); public boolean setColor (); )

Arayüz (yakın gelecekte daha ayrıntılı olarak tartışılacak) - bize sınıfın neye benzemesi gerektiğini, hangi yöntemleri içermesi gerektiğini, hangi değişkenlerin ve veri türlerinin işleneceğini söyler. Arayüzün kendisi yöntemleri uygulamaz, bunun yerine bu arayüzü genişletecek bir sınıf için bir iskelet oluşturur. Figure arayüzünü genişleten bir Figure sınıfı vardır:

Genel sınıf Figure, site.oop.inheritance.interfaces.Figürünü uygular.Figür( @Override public void Draw() ( //uygulaması gerekiyor) @Override public void delete() ( //uygulaması gerekiyor) @Override public void move(int piksel) ) ( //uygulama gerekiyor ) @Override public String getColor() ( return null; ) @Override public boolean setColor(String color) ( return false; ))

Bu sınıfta arayüzün tüm yöntemlerini uyguluyoruz Figür.

kamu sınıfı Şekil uygular site.oop.inheritance.interfaces.Şekil- bir anahtar kelime kullanma uygular arayüz yöntemlerini benimsiyoruz Figür Uygulama için.

Önemli: Bazıları henüz uygulanmamış olsa bile, sınıfın tüm arayüz yöntemlerine sahip olması gerekir, aksi takdirde derleyici bir hata verecek ve sizden tüm yöntemleri bağlamanızı isteyecektir. Yöntemlerin tamamı yalnızca arayüzde, burada yalnızca uygulamada değiştirilebilir.
@Geçersiz kıl- yöntemin geçersiz kılındığını belirten bir açıklama.

Buna göre, Figure sınıfından miras alınan figürlerin 3 sınıfına sahibiz. Figure sınıfı ana sınıftır ve Circle, Rectungle ve Triangle sınıfları alt sınıflardır.

Genel sınıf Circle, Figure'i genişletir ( @Override public void Draw() ( super.draw(); ) @Override public void delete() ( super.erase(); ) @Override public void move(int piksel) ( super.move( piksel); ) @Override public String getColor() ( return super.getColor(); ) @Override public boolean setColor(String color) ( return super..oop.inheritance.Figür( @Override public void Draw() ( super. Draw(); ) @Override public void delete() ( super.erase(); ) @Override public void move(int piksel) ( super.move(pixel); ) @Override public String getColor() ( return super.getColor (); ) @Override public boolean setColor(String color) ( return super..oop.inheritance.Figür( @Override public void Draw() ( super.draw(); ) @Override public void delete() ( super.erase (); ) @Override public void move(int piksel) ( super.move(pixel); ) @Override public String getColor() ( return super.getColor(); ) @Override public boolean setColor(String color) ( return super .setColor(renk); ))

genel sınıf Üçgen site.oop.inheritance.Figürünü genişletir- bu şu anlama gelir: sınıf Üçgen sınıfı miras alır Figür.

super.setColor(renk); - üst sınıftan yöntemleri çağırmanıza olanak tanıyan süper değiştirici.

Artık her sınıf, Figure sınıfının özelliklerini benimsemiştir. Bu bize tam olarak ne verdi?

Şekil sınıflarının geliştirme süresini önemli ölçüde azalttı ve ana sınıfın alanlarına ve yöntemlerine erişim sağladı.

Muhtemelen şu soru ortaya çıkıyor: ne uzanır farklı uygular?

Uzatır bize çok daha esnek bir yaklaşım sağlıyor. Yalnızca ihtiyacımız olan yöntemleri kullanırız, istediğimiz zaman yöntemin çerçevesini ve gövdesini değiştirebiliriz veya ana sınıftan gelen bilgileri kullanabilen ve yalnızca sınıfın gövdesini oluşturan tamamen yeni bir yöntem ekleyebiliriz.

Çocuk sınıflarında ilgimizi çeken yeni yöntemleri güvenle ekleyebiliriz. Örneğin Triangle sınıfına 2 yeni yöntem eklemek istiyoruz: flimYatay() Ve dikey Çevir ():

/** * Yeni Yöntem */ public void flipVertical () ( ); /** * Yeni Yöntem */ public void flipHorizontal () ( );

Şimdi bu 2 yöntem tamamen sınıfa ait Üçgen. Bu yaklaşım, temel sınıfın tüm sorunları çözemediği durumlarda kullanılır.

Veya farklı bir yaklaşım kullanabilir, alt sınıftaki yöntemleri değiştirebilir veya yeniden yazabilirsiniz:

Oldukça ilginç bir gerçek: Java'da çoklu kalıtım yasaktır, ancak sınıflardan herhangi biri varsayılan olarak o sınıftan miras alınır. Nesne. Yani herhangi bir sınıfı miras aldığımızda çoklu miras alırız)

Ama endişelenmeyin!

Adım 4.

Polimorfizm.

Daha genel olarak polimorfizm kavramı şu fikirdir: tek arayüz, birçok yöntem“.

Bu, bir grup ilgili eylem için ortak bir arayüz oluşturabileceğiniz anlamına gelir. Polimorfizmin avantajı, aynı arayüzün tek bir eylem sınıfını tanımlamak için kullanılmasına izin vererek program karmaşıklığının azaltılmasına yardımcı olmasıdır. Duruma bağlı olarak belirli bir eylemin seçimi derleyiciye aittir.

Bir programcı olarak bu seçimi kendiniz yapmak zorunda değilsiniz. Ortak arayüzü hatırlamanız ve kullanmanız yeterlidir.

Genel sınıf Parent ( int a = 2; ) genel sınıf Çocuk, Parent'i genişletir ( int a = 3; )

Öncelikle böyle bir duyurunun doğru olduğunu söylemek gerekiyor.

Mirasçılar, ebeveynleri ile aynı olsa bile herhangi bir isimle alan ilan edebilirler. Sınıf nesneleri Çocuk aynı anda iki değişken içerecektir ve yalnızca değer açısından değil aynı zamanda tür açısından da farklılık gösterebilecekleri için (sonuçta bunlar iki bağımsız alandır), hangi değerin kullanılacağını derleyici belirleyecektir.

Derleyici yalnızca alana erişmek için kullanılan referans türüne güvenebilir:

Çocuk c = yeni Çocuk(); System.out.println(c.a); // sonuç 3 olacaktır. Ebeveyn p = c; System.out.println(p.a); //sonuç 2 olacak

Bu reklamın adı " saklanmak" Ana alan varlığını sürdürür.

Açıkça erişilebilir:

Sınıf Çocuğu Parent'i genişletir ( int a = 3; //bildirimin gizlenmesi int b = ((Parent)this).a; //üst alana zahmetli erişim int c = super.a; //üst alana basit erişim)

Değişkenler B Ve C ana alanın değerlerini al A . Her ne kadar ifade ile Süper Daha basiti, miras ağacının iki üst düzeyine erişime izin vermeyecektir.

Ancak ebeveyn sınıfında bu alanın da gizlenmiş olması ve ebeveynin ebeveyninde başka bir değerin saklanmış olması oldukça olasıdır.

İçin yapıldığı gibi, açık bir atama ile erişilebilir B .

Sınıf Parent ( int x = 0; public void printX() ( System.out.println(x); ) ) class Child extends Parent ( int x = -1; )

Sonuç ne olacak yeniChild.printX(); ?

Yöntem, aşağıdaki gibi bir referans kullanılarak çağrılır: Çocuk , ancak yöntem sınıfta tanımlıdır Ebeveyn ve derleyici alana erişimi değerlendirir X bu yöntemde tam olarak bir sınıf alanı olarak Ebeveyn. Sonuç olacak 0 .

Yöntemin geçersiz kılınması durumunu düşünün:

Sınıf Parent ( public int getValue() ( return 0; )) class Child extends Parent ( public int getValue() ( return 1; )) Çocuk c = new Child(); System.out.println(c.getValue()); // sonuç 1 olacaktır. Ebeveyn p = c; System.out.println(p.getValue()); // sonuç 1 olacak

Ana yöntem tamamen geçersiz kılınır.

Bu temel özellik polimorfizm– mirasçılar, ebeveyn tipinin bir referansı ile erişilseler bile ebeveyn davranışını değiştirebilirler.

Eski yönteme dışarıdan erişilemese de, kullanılarak alt sınıfın içinden erişilebilir. Süper .

Statik alanlar gibi statik yöntemler de sınıfa aittir ve mirasçıların görünümü onları etkilemez. Statik yöntemler normal yöntemleri geçersiz kılamaz ve bunun tersi de geçerlidir.

Adım 5.

Soyutlama:

Makalenin başında da belirttiğimiz gibi soyutlama ve dolayısıyla soyut sınıflar ve yöntemler göz ardı edilemez.

OOP bağlamında soyutlama - hiyerarşide mevcut sınıftan daha yüksek bir tür için veri ve davranışın genelleştirilmesidir.

Değişkenleri veya yöntemleri bir alt sınıftan bir süper sınıfa taşıyarak, genelleştirmek onların. Bunlar genel kavramlardır ve Java dilinde uygulanabilir. Ancak dil aynı zamanda kavramları da ekler soyut sınıflar Ve soyut yöntemler.

Soyut bir sınıf, somutlaştırılamayan bir sınıftır.

Örneğin, bir Hayvan sınıfı oluşturabilirsiniz. Bu sınıfın örneğini yaratmanın bir anlamı yok: pratikte örnekler oluşturmanız gerekecek belirli sınıflarörneğin Köpek (köpek). Ancak tüm Hayvan sınıflarının ses çıkarma yeteneği gibi bazı ortak noktaları vardır. Hayvanın ses çıkarabilmesi hiçbir şey ifade etmez.

Üretilen ses hayvanın türüne bağlıdır.

Bu nasıl modellenir?

Soyut bir sınıfta genel davranışı tanımlayın ve alt sınıfların türlerine bağlı olarak belirli davranışları uygulamalarına neden olun.

Bir hiyerarşi aynı anda hem soyut hem de somut sınıfları içerebilir.

Soyutlamayı kullanma:

Person sınıfımız bazı davranış yöntemleri içeriyor ve buna ihtiyacımız olduğunu henüz bilmiyoruz. Bunu kaldıralım ve alt sınıfları bu davranışı polimorfik bir şekilde uygulamaya zorlayalım. Bunu Person'ın metodlarını soyut olarak tanımlayarak yapabiliriz. Daha sonra alt sınıflarımızın bu yöntemleri uygulaması gerekecek.

Public abstract class Person ( abstract void move(); abstract void talk(); ) public class Adult extends Person ( public Adult() ( ) public void move() ( System.out.println("Yürüdü."); ) public abstract class void talk() ( System.out.println("Spoke."); ) ) public class Baby, Kişiyi genişletir ( public Baby() ( ) public void move() ( System.out.println("Spoke."); ) genel geçersiz konuşma() ( System.out.println("Gurgled."); ) )

Yukarıdaki kodda ne yaptık?

Yöntemleri soyut olarak belirtmek için Person'ı değiştirdik ve alt sınıfları bunları uygulamaya zorladık.
Adult'ı Person'ın alt sınıfı haline getirdik ve bu yöntemleri uyguladık.
Baby'yi Person'ın alt sınıfı haline getirdik ve bu yöntemleri uyguladık.

Bir yöntem özeti bildirerek, alt sınıfların ya yöntemi uygulamasını ya da bu alt sınıflardaki yöntemi soyut hale getirmesini ve yöntemi uygulama sorumluluğunu sonraki alt sınıflara aktarmasını gerektirir. Soyut bir sınıfta bazı yöntemleri uygulayabilir ve geri kalanını alt sınıfların uygulamasını sağlayabilirsiniz. O size bağlı. Uygulamak istemediğiniz yöntemleri soyut olarak bildirmeniz ve yöntem gövdesi sağlamamanız yeterlidir. Bir alt sınıf, bir süper sınıfın soyut yöntemini uygulamazsa, derleyici bir hata verecektir.

Artık Yetişkin ve Bebek, Person sınıfının alt sınıfları olduğundan, her sınıfın bir örneğine Person türü olarak başvurabiliriz.

Bilgisayar teknolojisi geliştikçe bilgisayarlar giderek daha karmaşık sorunları çözmek için kullanılmaya başlandı. Karmaşık sorunları çözmek için yalnızca bilgisayarların artan bilgi işlem gücünün değil, aynı zamanda karmaşık program yazma verimliliğinin de önemli olduğu ortaya çıktı. Nesne yönelimli programlama(OOP), karmaşık programlar oluştururken ortaya çıkan zorlukların üstesinden gelmenin tam olarak etkili bir yolu olarak ortaya çıktı.

OOP'un en önemli kısmı, karmaşık programlama problemlerini çözmeye yönelik özel bir yaklaşımdır. nesne yönelimli analiz ve nesne yönelimli programlama dilleri bu yaklaşımın uygulanması için basitçe uygun araçlardır.

Hikaye

OOP'un kurucuları seçkin Norveçli bilim adamları Cristen Nygaard ve Ole-Johan Dahl'dır. Nygaard, navigasyon simülasyonları üzerinde çalışırken, mevcut yazılım araçlarının bu tür karmaşık programlar oluşturmada etkisiz olduğunu fark etti ve ardından Nygaard, daha sonra adı verilen karmaşıklığın engellerini aşacak yeni programlama için konseptler geliştirmeye başladı. nesne odaklı(terimin kendisi Java dilinin yazarı Alan Kay tarafından türetilmiştir). Nygaard, Ole-Johan Dahl ile birlikte OOP'nin temel ilkelerini ve bunların uygulanmasına yönelik pratik mekanizmaları geliştirdi ve bunlar daha sonra ilk OOP Simula'sında somutlaştırıldı. Bu bilim adamlarının erdemleri dünya bilim camiası tarafından takdir edildi ve 2001'de Nygaard ve Dahl, bilgisayar bilimi alanında Nobel Ödülü'nün bir tür benzeri olan Alan Turing Ödülü'nün sahibi oldular.

Simula dili akademik çevrelerde ünlüydü ancak çeşitli nedenlerden dolayı ticari yazılım geliştiricileri arasında popülerlik kazanamadı. Bununla birlikte, OOP'un temel fikirleri ve yetenekleri programcılar için çok çekiciydi. Daha sonra diğer OY'ler oluşturuldu: SmallTalk (1980), C++ (1985), Eiffel (1986), Object Pascal (1986) ve Delphi (1995), Oberon-2 (1991), Java (1991), Visual Basic (1991) ve daha birçokları. Bu dillerden bazıları programlamada endüstri standardı haline geldi.

OOP'un özellikleri

OOP'un ana fikri, davranışı ve etkileşimi gerçek dünyadaki nesnelerin davranışını ve etkileşimini taklit eden yazılım yapıları oluşturmaktır (yani, programda gerçek varlıkların sanal analogları oluşturulur). Nesne yönelimli programlama dilleri bu yaklaşımın hızlı ve kolay bir şekilde uygulanmasına olanak sağlamalıdır.

Günlük yaşamda insanlar, karmaşık olayları basit kavramlarla anlamalarına ve ifade etmelerine olanak tanıyan çeşitli "düşünme ekonomisi" tekniklerini (bilinçsizce bile) kullanırlar. Tipik “düşünme ekonomisi” teknikleri şunlardır:

· soyutlama (önemsiz ayrıntıların atılması);

· genelleme (farklı olay veya nesnelerin ortak temel özelliklerinin tanımlanması);

· sınıflandırma (olgular arasındaki bağlantının ve benzerlik derecelerinin farkındalığı).

Bu basit teknikler, kişinin söz konusu olgunun karmaşıklığıyla başa çıkmasına yardımcı olur. Ve nesne yönelimli programlama dilleri de programların "karmaşıklığıyla mücadele etmek" için benzer araçlar sağlamalıdır. Nesne yönelimli yaklaşımı uygulamak için programlama dillerine yeni kavramlar eklenmiştir:

· nesneler - verileri ve bunları işlemek için algoritmaları birleştiren özel program yapıları;

· kapsülleme - nesnelerin işleyişinin ayrıntılarının gizlenmesi;

· miras, yeni sınıflar yaratmanın “kısayol” yoludur;

· polimorfizm - bir fonksiyonun çeşitli uygulamalarını kullanma yeteneği.

Nesneler ve sınıflar

Nesneler veri ve algoritmalardan oluşan özel yazılım birimleridir. tam olarak bu verileri işlemek için. Bir nesnenin içerdiği verilere denir alanlar(nitelikler, özellikler, üyeler). Nesnenin içerdiği algoritmalara denir yöntemler(hizmetler, işlemler, üye işlevleri). Ne yazık ki OOP'ta yerleşik tek bir terminoloji yoktur ve farklı diller aynı kavramları belirtmek için farklı terimler kullanır.

Sınıflar- Bunlar nesne veri türleridir. Tamsayılar bir tamsayı türüne (tamsayı veya bayt gibi) ait olduğu gibi, nesneler de sınıf adı verilen bir nesne türüne aittir. Aynı sınıftaki tüm nesneler aynı alan kümesine ve aynı yöntem kümesine sahiptir.

Bazı dillerde (C++, Java) nesnelere denir. sınıfın örnekleri(örnekler).

Sınıfları ve nesneleri kullanmanın faydası, veriler ile veri işlemeye yönelik işlevler arasındaki mantıksal (anlamsal) yazışmanın kontrol edilmesinin önemsiz bir görev haline gelmesi ve büyük ölçüde derleyiciye (bilgisayar) devredilebilmesidir - artık verilerin yanlış kullanımını kendisi belirleyebilir.

Kapsülleme

Kapsülleme (kelimenin tam anlamıyla "gizleme"), bir sınıfın iç yapısı hakkındaki bilgilerin kontrollü olarak gizlenmesidir. Bir sınıfta, nesnelerin yalnızca çalışmalarını sağlamak için kullandıkları alanlar ve yöntemler bulunabilir (örneğin, dinamik bellekte bir arabellek, çalışma verilerini içeren bir dosya, bu dosyayla çalışma yöntemleri vb.). Bu tür alanları değiştirmek veya nesnenin dışından yöntemleri çağırmak tehlikelidir; bu, nesnenin çalışma durumunu bozabilir. Nesnelerin güvenliğini sağlamak için bu tür alanlar ve yöntemler saklamak- bunlara dışarıdan erişimi yasaklayın.

"Karmaşıklıkla mücadele" açısından bakıldığında kapsülleme, nesnelerin doğru çalışması üzerindeki kontrolün bir kısmını derleyiciye (bilgisayar) kaydırmanıza olanak tanır.

Farklı TOE'ler, alanları ve yöntemleri kapsüllemek için farklı seçenekler sunar (tamamen yokluktan tüm alanların otomatik olarak gizlenmesine kadar). C++, Java, Delphi, Eiffel vb. gibi endüstriyel OAL'lerde alanların ve yöntemlerin üç düzeyde kapsüllenmesi vardır:

· genel - hitap etmek kamu alanları ve nesne yöntemlerinde herhangi bir kısıtlama yoktur;

korumalı - doğrudan erişim korunan alanlar ve yöntemler yalnızca bu sınıfın yöntemlerinden ve alt sınıfların yöntemlerinden mümkündür;

özel - doğrudan erişim özel alanlar ve yöntemler yalnızca bu sınıfın yöntemlerinden mümkündür.

Miras

Miras- Eşleşen öğelerin açıklamalarını atlayarak yalnızca mevcut sınıflardan farklılıkları ekleyerek yeni sınıflar oluşturmak. Kalıtım sırasında yeni sınıf çağrılır çocuk sınıfı(türetilmiş, çocuk, alt sınıf) ve orijinal sınıf çağrılır ata sınıfı(temel, ebeveyn, süper sınıf).

Kalıtım, yinelenen bildirimleri ortadan kaldırarak program boyutunu azaltır. Ata sınıfta bildirilen tüm alanlar ve yöntemler otomatik olarak alt sınıfa aktarılır ve genellikle çağrılır. miras(miras).

Gerekirse herhangi bir ana yöntem kullanılabilir. yeniden tanımla- yani alt sınıftan aynı adı taşıyan bir yöntemin çağrılması durumunda başka bir algoritmanın yürütülmesini atayın.

Bazı OY'ler destekliyor çoklu kalıtım Türetilmiş bir sınıfın tüm özellikleri ve yöntemleri aynı anda birkaç sınıftan devraldığı. Ne yazık ki, çoklu kalıtım birçok mantıksal çatışma durumuyla doludur ve desteği, programlama dilini ve özellikle de derleyiciyi karmaşık hale getirir. Bu nedenle birçok OOY'de çoklu kalıtım yasaktır, ancak simüle edilebilir.

Tüm ata ve soyundan gelen sınıfların kümesine denir sınıf hiyerarşisi.

Sınıf mirası, OOP'nin merkezi kavramıdır; diğer tüm kavram ve mekanizmalar doğrudan veya dolaylı olarak buna dayanmaktadır. OOP mekanizmalarının büyük çoğunluğu, faydalarını göstermek için sınıf hiyerarşilerinin oluşturulmasını gerektirir.

Polimorfizm

Polimorfizm(kelimenin tam anlamıyla - “çeşitli formlar”) - benzer bir amaca sahip birkaç yöntem (veya işlev) için tek bir adı kullanma yeteneği. Başka bir yorum, bir yöntemin (fonksiyonun) birden fazla uygulama seçeneğine sahip olabileceği yönündedir; böyle bir yönteme (işlev) denir polimorfik. Diğer OOP mekanizmaları gibi polimorfizm de karmaşık programların geliştirilmesini basitleştirmenin bir yoludur. Aslında polimorfizm kavramı birbirinden ayırıyor Ne yapılması gerekiyor çünkü Nasıl bu yapılmalıdır.

Gerçek hayatla bir benzetme yaparsak, polimorfizm genelleştirilmiş eylemlere karşılık gelir. Örneğin “müzik çalmak” fiili “müzik aleti çalmak” anlamına gelir. Ancak farklı müzik aletleri farklı şekilde çalınır. Bir terim var, ancak eylem için birçok seçenek var. Yani, "müzik çal" - polimorfik eylem. OOP'ta "müzik çal" eylemi şuna karşılık gelir: polimorfik yöntem Her müzik enstrümanı sınıfı için kendi uygulamaları vardır.

OOP'ta iki tür polimorfik yöntem vardır: aşırı yüklenmiş Ve sanal.

Aşırı Yüklenmiş Yöntemler gerçekleştirmek için tasarlandı farklı türdeki verilerle. Aynı adlara sahiptirler ancak bağımsız değişken listeleri ve/veya dönüş türleri farklıdır.

Sanal yöntemler gerçekleştirmek için tasarlandı anlam bakımından aynı olan işlemlerİlgili ancak aynı olmayan sınıfların nesnelerinde. Sanal yöntemler aynı adlara ve prototiplere sahiptir. Ana özellikleri, her zaman nesnenin gerçek sınıfına tam olarak karşılık gelmeleridir.

Aşırı yüklenmiş işlevlerin tipik bir örneği Pascal'daki SQR işlevidir. Bir sayının karesini hesaplar ve tam sayı argümanları için sonuç da tam sayı olacaktır ve gerçek argümanlar için sonuç gerçek olacaktır.

Sanal yöntemlerin faydaları yalnızca sınıf hiyerarşisi kullanıldığında ortaya çıkar. Sanal yöntemlerin tipik bir kullanımı aşağıdaki gibidir:

· Hiyerarşinin ata sınıfında, bazı yararlı eylemleri tanımlayan polimorfik bir yöntem bildirilir. Bu durumda ya sanal bir yöntem kullanır ya da kendisi sanaldır.

· Alt sınıflarda karşılık gelen sanal yöntem geçersiz kılınır - her alt sınıf için bu yararlı eylem kendi yöntemiyle gerçekleştirilir.

· Bir alt sınıfa ait bir nesne üzerinde polimorfik bir yöntem çağırdığınızda, aslında alt sınıfın sanal yöntemi (ata sınıfın değil) kullanılır.

Sanal yöntemlerin bu şekilde kullanılmasının çarpıcı bir örneği Delphi veya Visual Basic grafik pencere arayüzü sistemidir: grafik arayüzün görünür her öğesi bir düğme, kaydırıcı, pencere vb.'dir. - TControl sınıfının soyundan olmalıdır. TControl sınıfı, GUI öğelerini çizmek için yaygın polimorfik yöntemler sunar ve onun alt öğelerinden herhangi biri, ekranda kendi yöntemleriyle kendilerini çizebilir.

Nesne yönelimli programlamadan 2004 Standardında açıkça bahsedilmemektedir, ancak böyle bir konu uzman kurumların öğrencileri için Bilgisayar Bilimleri Eğitiminin Zorunlu Asgari İçeriğinde (Seviye B) mevcuttu: Nesneye yönelik programlama: nesne, nesne özellikleri, nesne üzerindeki işlemler. Orada nesne yönelimli programlama teknolojisinden de bahsedilmişti.

Bununla birlikte, OOP yalnızca birçok okulda bilgisayar bilimi (programlama) öğretme uygulamasının bir parçası haline gelmekle kalmamış, aynı zamanda okul ders kitaplarının sayfalarında da mevcuttur ( Ugrinoviç N.D. Bilgisayar bilimi ve bilgi teknolojisi. 10–11. Sınıflar için ders kitabı, 2005. M.: BINOM. Bilgi Laboratuvarı). Ayrıca kavramların nesne ve o özellikler.

OOP teknolojisi (paradigma), modern programlama tekniklerine çok fazla hakim olmayı değil, çözülen problemin bir nesne modelini geliştirme yeteneğini gerektirir. Bu, OOP'un temel ilkeleri ve genel olarak programlama hakkında iyi bilgi gerektirir, ancak herhangi bir OOP bilgisi zorunlu değildir - OOP'un kurucuları ve teorisyenleri bunun hakkında defalarca yazmışlardır. Grady Booch, “Nesne Yönelimli Tasarım ve Analiz” adlı kitabında şu düsturu ifade ediyor: “Nesne yönelimli olmayan herhangi bir programlama dilinde, nesne yönelimli tarzda programlar yazabilirsiniz.” OOP teknolojisini kullanarak bir algoritma oluşturmak için, algoritmanın birlikte çalıştığı nesnelerin bir listesini oluşturmanız, her nesnenin özelliklerini düşünmeniz ve algoritmayı, açıklanan nesnelerin etkileşimi olarak uygulamanız gerekir.

Makalede daha önce de belirtildiği gibi, bu yaklaşım karmaşık sorunların çözümünü basitleştirir, ancak bir okul içinde (sınırlı saat sayısı göz önüne alındığında), öğrenciler için OOP teknolojisinin kullanımını zorunlu olarak gerektirmeyecek anlamlı öğrenme görevleri bulmak zordur. en dolu.

Aslında, okuldaki OOP, modern profesyonel programlama sistemlerinde yalnızca görsel ve bileşen programlamanın ayrılmaz bir parçası olarak kabul edilir ve nesneler olarak çeşitli seviyelerde hazır nesne kitaplıkları kullanılır - bunlar, Windows uygulamaları için grafiksel bir arayüz oluşturmaya yönelik kitaplıklardır; ve çok amaçlı evrensel veri türü kitaplıkları (örneğin, C++'daki STL). Bu kütüphanelerin ilkel kullanımı için programlama dili sözdiziminin birkaç basit kuralını bilmek ve uygulayabilmek yeterlidir. Ancak bu tür “bilgi” hiçbir şekilde öğrencileri bir programlama dilinin profesyonel ustalığına, hatta OOP anlayışına yaklaştırmaz. Ama görünüşe göre bunda yanlış bir şey yok. Okul bilgisayar bilimi, uzmanlaşmış bir okulda bile profesyonel programcılar yetiştirmeyi amaçlamaz. OOP'nin öğretilmesi özel bir konudur; üniversitelerde ilgili uzmanlık alanlarında bile sıklıkla yeterince ayrıntılı olarak çalışılmamaktadır.

Bazı bilgisayar bilimleri öğretmenlerinin, okul da dahil olmak üzere programlama eğitiminde nesne yönelimli yaklaşımı ön plana koyma önerisini tamamen reddetmeden, program, yürütücü, değişken, koşul, döngü vb. gibi temel kavramlar olmadan OOP'nin imkansız olduğunu belirtiyoruz. . OOP kavramı aynı zamanda klasik prosedürel programlamayı da içerir (bkz. Altprogramlar”, tıpkı Einstein'ın mekaniği - Newton'un mekaniği gibi: prosedürel bir programı, basitlik amacıyla adı çıkarılmış tek bir nesne olarak hayal etmek yeterlidir. Bu nedenle okuldaki programlama dersinin görevi öncelikle temel şeyleri öğretmektir. Ve yalnızca modern görsel programlama ortamlarıyla (Delphi, Visual Basic, Visual C++) çalışmak mümkünse
vb.) nesneler kavramını ve bunların kullanımını esas olarak “model tabanlı” programlama öğretim yöntemiyle tanıtırlar.

Nesneye yönelik programlama (OOP), Java'nın temelini oluşturur. Aslında tüm Java programları bir dereceye kadar nesne yönelimlidir. Java dili OOP ile o kadar yakından ilişkilidir ki, en basit programları bile yazmaya başlamadan önce OOP'un temel prensiplerini öğrenmelisiniz. Bu nedenle OOP'un teorik konularını ele alarak başlayalım.

İki teknik

Tüm bilgisayar programları iki öğeden oluşur: kod ve veri. Dahası, bir program kavramsal olarak kendi kodu veya verileri etrafında düzenlenebilir. Başka bir deyişle, bazı programların organizasyonu "ne olduğu" ile belirlenirken, diğerleri "neyin etkilendiği" ile belirlenir. Program oluşturmanın iki yöntemi vardır. Bunlardan ilki denir süreç odaklı model ve bir programı doğrusal adımlardan oluşan bir dizi (yani kod) olarak karakterize eder. Süreç odaklı model şu şekilde görülebilir: Verilere etki eden kod. Bu model, C gibi prosedürel dillerde oldukça başarılı bir şekilde kullanılmıştır. Ancak Bölüm 1'de belirtildiği gibi, bu yaklaşım, programların artan boyutu ve karmaşıklığı nedeniyle bir takım zorlukları da beraberinde getirmektedir.

Program karmaşıklığındaki artışın üstesinden gelmek için, adı verilen bir yaklaşımın geliştirilmesi nesne yönelimli programlama. Nesne yönelimli programlama, bir programı kendi verileri (yani nesneler) ve bu verilerle iyi tanımlanmış bir dizi arayüz etrafında düzenlemenize olanak tanır. Nesneye yönelik bir program karakterize edilebilir koda erişimi kontrol eden veriler olarak. Daha sonra tartışılacağı gibi, veri yönetimi işlevlerinin dış kaynaklardan sağlanması çeşitli kurumsal faydalar sağlayabilir.

Soyutlama

OOP'nin önemli bir unsuru soyutlama. Karmaşık olguları ve nesneleri soyutlamaya başvurarak temsil etmek insan doğasıdır. Örneğin insanlar bir arabayı onbinlerce ayrı parçadan oluşan bir koleksiyon olarak değil, kendine has davranışı olan tamamen spesifik bir nesne olarak hayal ederler. Bu soyutlama, örneğin mağazaya giderken arabayı oluşturan parçaların karmaşıklığı hakkında düşünmek zorunda kalmanızı önler. Motor, şanzıman ve fren sisteminin ayrıntılarını göz ardı edebilirsiniz. Bunun yerine nesne tek bir birim olarak kullanılabilir.

Hiyerarşik sınıflandırmalar soyutlamayı uygulamanın etkili bir yoludur. Bu, karmaşık sistemlerin anlambilimini basitleştirmeyi ve onları daha yönetilebilir parçalara ayırmayı mümkün kılar. Dışarıdan araba tek bir nesneye benziyor. Ancak içeriye baktığınızda, bunun birkaç alt sistemden oluştuğu anlaşılıyor: direksiyon, frenler, ses sistemi, emniyet kemerleri, ısıtıcı, navigasyon cihazı vb. Bu alt sistemlerin her biri daha uzmanlaşmış birimlerden oluşur. Örneğin bir ses sistemi bir radyo, CD çalar ve/veya ses kasetlerinden oluşur. Bütün bunların amacı, bir arabanın (veya başka herhangi bir karmaşık sistemin) yapısının hiyerarşik soyutlamalar kullanılarak tanımlanabileceğidir.

Karmaşık sistemlerin hiyerarşik soyutlamaları bilgisayar programlarına da uygulanabilir. Soyutlama yoluyla, geleneksel süreç odaklı bir programın verileri kendisini oluşturan nesnelere dönüştürülebilir ve süreç adımlarının sırası, bu nesneler arasında iletilen bir dizi mesaja dönüştürülebilir. Böylece bu nesnelerin her biri kendine özgü davranışı tanımlar. Bu nesneler, kendilerine talimat veren mesajlara yanıt veren somut varlıklar olarak düşünülebilir. Belirli bir eylemi açıklayın. Aslında OOP'un özü budur.

OOP ilkeleri hem Java dilinin hem de insanın dünya algısının temelini oluşturur. Bu ilkelerin programlarda nasıl uygulandığını anlamak önemlidir. Daha sonra açıklığa kavuşturulacağı gibi, OOP, genel tasarımın başlangıcı, geliştirilmesi ve olgunlaşması da dahil olmak üzere, herhangi bir büyük yazılım projesinin yaşam döngüsüne eşlik eden kaçınılmaz değişikliklere dayanabilen programlar oluşturmak için başka ama daha etkili ve doğal bir tekniktir. Örneğin, dikkatlice tanımlanmış nesneleriniz ve bu nesnelere yönelik net, güvenilir arayüzleriniz varsa, eski sistemin parçalarını güvenli ve kolay bir şekilde kaldırabilir veya değiştirebilirsiniz.

OOP'nin üç ilkesi

Tüm nesne yönelimli programlama dilleri, nesne yönelimli modelin uygulanmasını kolaylaştıracak mekanizmalar sağlar. Bu mekanizmalar kapsüllenme, kalıtım ve polimorfizmdir. Bu OOP ilkelerine ayrı ayrı bakalım.

Kapsülleme

Kodu ve onun işlediği verileri birbirine bağlayan, hem dış müdahalelerden hem de kötüye kullanımdan koruyan mekanizmaya ne ad verilir? kapsülleme. Kapsülleme, kodu ve verileri kabuk dışındaki diğer kodların rastgele erişiminden koruyan koruyucu bir kabuk olarak düşünülebilir. Kabuk içindeki koda ve verilere erişim, dikkatlice tanımlanmış bir arayüz tarafından sıkı bir şekilde kontrol edilir. Gerçek dünyadan bir benzetme yapmak için, bir arabadaki otomatik şanzımanı düşünün. Hızlanma miktarı, sürdüğü yüzeyin dikliği ve vites kolunun konumu da dahil olmak üzere araç hakkında birçok bilgiyi içerir. Kullanıcı (bu durumda sürücü) bu karmaşık kapsüllemeyi yalnızca tek bir yolla etkileyebilir: vites kolunu hareket ettirerek. Vites kutusu örneğin sinyal lambası veya ön cam sileceklerinden etkilenmemelidir. Böylece vites kolu, vites kutusuyla kesin olarak tanımlanmış ve aslında tek arayüzdür. Üstelik vites kutusunun içinde olup bitenler, dışarıdaki nesneleri etkilemiyor. Örneğin vites değiştirmek farları açmaz! Otomatik vites değiştirme işlevi kapsüllenmiştir, böylece düzinelerce otomobil üreticisi bunu istedikleri gibi uygulayabilir. Ancak sürücünün bakış açısından tüm bu vites kutuları aynı şekilde çalışır. Benzer bir prensip programlamada da uygulanabilir. Kapsüllenmiş kodun gücü, herkesin ona nasıl erişeceğini bilmesidir ve bu nedenle uygulama ayrıntılarına bakılmaksızın ve beklenmedik yan etkilerden korkmadan kullanılabilir.

Ejava kapsüllemenin özü sınıftır. Sınıflar sonraki bölümlerde daha ayrıntılı olarak tartışılacaktır, ancak o zamana kadar bunların en azından kısa bir tanımını vermek faydalı olacaktır. Sınıf bir dizi nesne tarafından paylaşılacak yapıyı ve davranışı (veri ve kod) tanımlar. Belirli bir sınıfın her nesnesi, sanki nesne sınıfın kalıbında "dökülmüş" gibi, sınıf tarafından tanımlanan yapı ve davranışı içerir. Bu nedenle bazen nesnelere denir sınıfın örnekleri. Dolayısıyla bir sınıf mantıksal bir yapıdır ve bir nesne de onun fiziksel düzenlemesidir.

Bir sınıf oluşturduğunuzda, sınıfı oluşturan kodu ve verileri tanımlarsınız. Bu unsurlara birlikte denir üyeler sınıf. Özellikle, bir sınıfta tanımlanan verilere denir üyelerini değiştir, veya örnek değişkenler, ve veriler üzerinde çalışan kod üye yöntemleri ya da sadece yöntemler.(Java programcıları buna ne diyor yöntemler, C/C++ programcıları çağırıyor işlevler) Java'da düzgün bir şekilde yazılmış programlarda yöntemler, üye değişkenlerin nasıl kullanıldığını tanımlar. Bu, bir sınıfın davranışının ve arayüzünün, örneğinin verileri üzerinde çalışan yöntemler tarafından belirlendiği anlamına gelir.

Bir sınıfın amacı karmaşık program yapısını kapsüllemek olduğundan, sınıfın kendi içinde karmaşık uygulama yapısını gizleyecek mekanizmalar vardır. Bir sınıftaki her yöntem veya değişken, özel veya genel olarak işaretlenebilir. Açık Bir sınıfın arayüzü, sınıfın dış kullanıcılarının bilmesi gereken veya bilebileceği her şeyi temsil eder. Kapalı yöntemlere ve verilere yalnızca belirli bir sınıfın üyesi olan kod tarafından erişilebilir. Bu nedenle bu sınıfın üyesi olmayan herhangi bir kod, özel yönteme veya değişkene erişemez. Bir sınıfın özel üyelerine, programın diğer bölümlerine yalnızca sınıfın genel yöntemleri aracılığıyla erişilebilir ve böylece yasa dışı eylemler gerçekleştirme olasılığı ortadan kaldırılır. Bu elbette halka açık arayüzün dikkatli bir şekilde tasarlanması ve sınıfın iç işleyişine ilişkin gereksiz ayrıntıları açığa çıkarmaması gerektiği anlamına gelir (Şekil 1).

Pirinç. 1.

Miras

Bir cismin diğer bir cismin özelliklerini kazanmasına ne ad verilir? miras. Bu OOP'nin çok önemli bir ilkesidir çünkü kalıtım hiyerarşik sınıflandırma ilkesini sağlar. Daha önce belirtildiği gibi, çoğu bilgi hiyerarşik (yani yukarıdan aşağıya) sınıflandırma yoluyla asimilasyona açık hale gelir. Örneğin, Golden Retriever sınıflandırmanın bir parçasıdır. köpekler, bu da sınıfa ait memeliler, ve bu - daha da büyük bir sınıfa hayvanlar. Hiyerarşiler olmasaydı, her nesnenin tüm özelliklerini açıkça tanımlaması gerekirdi. Ancak kalıtım sayesinde bir nesnenin yalnızca onu sınıfta özel kılan şeyleri tanımlaması gerekir. Bir nesne, ortak niteliklerini ana nesnesinden miras alabilir. Böylece miras mekanizması, bir nesneyi daha genel bir durumun özel durumu haline getirmenize olanak tanır. Bu mekanizmayı daha ayrıntılı olarak ele alalım.

Kural olarak çoğu insan çevrelerindeki dünyayı hayvanlar, memeliler ve köpekler gibi hiyerarşik olarak birbirine bağlı nesneler biçiminde algılar. Hayvanların soyut bir tanımını yapmak isterseniz, onların belirli özelliklere sahip olduğunu söyleyebilirsiniz: büyüklük, zeka düzeyi ve iskelet sistemi. Hayvanların da belirli davranışsal özellikleri vardır: Yemek yerler, nefes alırlar ve uyurlar. Özelliklerin ve davranışın bu açıklaması bir tanım oluşturur. sınıf hayvanlar.

Memeliler gibi daha spesifik bir hayvan sınıfını tanımlayacak olsaydık, dişlerin ve meme bezlerinin türü gibi daha spesifik özellikleri belirtmemiz gerekirdi. Bu tanım denir alt sınıf ait olan hayvanlar üst sınıf(ebeveyn sınıfı) memeliler. Ve memeliler yalnızca daha kesin olarak tanımlanmış hayvanlar olduğundan, miras almak hayvanların tüm özellikleri. Daha düşük seviyeli alt sınıf sınıf hiyerarşisi ana sınıflarının her birinin tüm özelliklerini miras alır (Şekil 2).

Pirinç. 2.

Kalıtım aynı zamanda kapsülleme ile de ilgilidir. Tek bir sınıf belirli özellikleri kapsıyorsa, bu sınıfın herhangi bir alt sınıfı aynı özelliklere sahip olacaktır. artı uzmanlığını belirleyen ek olanlar (Şekil 3). Bu temel prensip nedeniyle, nesne yönelimli programların karmaşıklığı geometrik ilerlemeden ziyade aritmetik ilerlemeyle artar. Yeni alt sınıf, tüm üst sınıflarının niteliklerini miras alır ve bu nedenle sistem kodunun geri kalanının çoğuyla öngörülemeyen etkileşimlere sahip değildir.

Pirinç. 3. Labradorit tüm ana hayvan sınıflarının kapsüllenmiş özelliklerini tamamen miras alır

Polimorfizm

Polimorfizm(Yunanca “birçok formdan”) aynı arayüzün ortak bir eylem sınıfı için kullanılmasına izin veren bir OOP ilkesidir. Her eylem belirli duruma bağlıdır. Örnek olarak ters depo listesi görevi gören bir yığını düşünün. Diyelim ki bir program üç tür yığına ihtiyaç duyuyor: tamsayı değerler için, kayan noktalı sayısal değerler için ve karakterler için. Bu yığınların her biri için uygulama algoritması, içinde depolanan verilerdeki farklılıklara rağmen aynı kalır. Nesne yönelimli olmayan bir dilde, yığının işlenmesi, ayrı adlar altında üç farklı yardımcı program kümesinin oluşturulmasını gerektirir. Java'da, polimorfizm ilkesi sayesinde, yığının aynı ortak adlar altında işlenmesi için ortak bir yardımcı programlar kümesi tanımlanabilir.

Daha genel olarak, polimorfizm ilkesi sıklıkla "tek arayüz, çoklu yöntem" ifadesiyle ifade edilir. Bu, birbiriyle ilişkili bir grup aktivite için ortak bir arayüz geliştirmenin mümkün olduğu anlamına gelir. Bu yaklaşım, programın karmaşıklığını azaltır, çünkü belirtmek için aynı arayüz kullanılır. genel eylem sınıfı. Ve seçim özel eylem(yani yöntem) her duruma göre yapılır ve derleyicinin sorumluluğundadır. Bu, programcıyı bu seçimleri manuel olarak yapma zorunluluğundan kurtarır. Sadece genel arayüzü hatırlaması ve doğru şekilde uygulaması gerekiyor.

Analojiyi köpeklerle sürdürürsek köpeğin koku alma duyusunun polimorfik bir özellik olduğunu söyleyebiliriz. Bir köpek bir kedinin kokusunu alırsa havlar ve onu kovalar. Ve eğer köpek yemeğin kokusunu alırsa tükürüğü akmaya başlayacak ve kasesine doğru koşacaktır. Her iki durumda da aynı koku alma duyusu çalışır. Tek fark, kokuyu tam olarak neyin yaydığıdır; köpeğin burnunu etkileyen veri tipinde! Bu genel prensip, bir Java programındaki yöntemlere uygulanarak uygulanabilir.

Polimorfizm, kapsülleme ve kalıtımın birlikte kullanımı

Polimorfizm, kapsülleme ve kalıtım ilkeleri doğru şekilde uygulandığında, bunlar birlikte süreç odaklı bir modele göre daha sağlam ve ölçeklenebilir programların geliştirilmesini destekleyen bir programlama ortamı oluşturur. Dikkatlice tasarlanmış bir sınıf hiyerarşisi, geliştirmek ve test etmek için zaman ve çaba harcadığınız kodu yeniden kullanmak için güçlü bir temel sağlar. Kapsülleme, uygulamada kullanılan sınıfların genel arayüzüne bağlı olan kodu bozmadan önceden oluşturulmuş uygulamalara geri dönmenizi sağlar. Ve polimorfizm açık, pratik, okunabilir ve kararlı kod oluşturmanıza olanak tanır.

Daha önce verilen iki gerçek hayat örneğinden araba örneği, OOP'nin yeteneklerini daha iyi göstermektedir. Köpek örneği, OOP'yi kalıtım açısından ele almak için oldukça uygun olsa da, araba örneğinin programlarla daha fazla ortak noktası vardır. Çeşitli türdeki (alt sınıflardaki) arabaları sürerken, tüm sürücüler kalıtımı kullanır. Araç ister okul otobüsü, ister binek otomobil, spor otomobil veya aile minivanı olsun, tüm sürücüler direksiyon simidini, frenleri ve gaz pedalını kolaylıkla bulup kullanabilecek. Vites koluyla biraz oynayarak, çoğu kişi, ikisinin ortak ebeveyn sınıfı olan şanzıman sistemini net bir şekilde anladıkları sürece, manuel şanzıman ile otomatik şanzıman arasındaki farkları bile anlayabilir.

İnsanlar araba kullanırken sürekli olarak kapsüllenmiş özellikleriyle etkileşime girerler. Fren ve gaz pedalları, karşılık gelen nesnelerin inanılmaz karmaşıklığını o kadar basit bir arayüzün arkasına gizler ki, bu nesneleri kontrol etmek için sadece ayağınızla pedala basmanız yeterlidir! Spesifik motor uygulamasının, fren tipinin ve lastik boyutunun, pedal sınıfının belirlenmesiyle etkileşimi üzerinde hiçbir etkisi yoktur.

Son olarak polimorfizm, otomobil üreticilerinin temelde aynı araç için çok çeşitli seçenekler sunma yeteneğini açıkça yansıtmaktadır. Örneğin araç, kilitlenmeyi önleyici frenler veya geleneksel frenler, hidrolik direksiyon veya kremayer ve pinyonlu direksiyon ve 4, 6 veya 8 silindirli motorlarla donatılabilir. Ancak her durumda, durmak için fren pedalına basmanız, dönmek için direksiyonu çevirmeniz ve arabanın daha hızlı hareket etmesini sağlamak için gaz pedalına basmanız gerekecektir. Aynı arayüz çok çeşitli uygulamaları kontrol etmek için kullanılabilir.

Gördüğünüz gibi kapsülleme, kalıtım ve çokbiçimlilik ilkelerinin bir arada uygulanması sayesinde tek tek parçalar araba adı verilen bir nesneye dönüştürülebiliyor. Aynı durum bilgisayar programları için de geçerlidir. OOP ilkeleri birçok ayrı parçadan tutarlı, güvenilir ve sürdürülebilir bir program oluşturmayı mümkün kılar.

Bu bölümün başında belirtildiği gibi her Java programı nesne yönelimlidir. Daha doğrusu, her Hajava programı kapsülleme, kalıtım ve polimorfizm ilkelerini uygular. İlk bakışta, bu ilkelerin tümü, bu bölümün geri kalanında ve sonraki birkaç bölümde verilen kısa örnek programlarda yer almıyor gibi görünebilir, ancak yine de bunlarda mevcuttur. Daha sonra açıklığa kavuşturulacağı gibi, birçok Java dili özelliği, kapsülleme, kalıtım ve polimorfizm ilkelerinden kapsamlı bir şekilde yararlanan yerleşik sınıf kitaplıklarının bir parçasıdır.

Nesne yönelimli programlama (OOP) kavramı, prosedürel programlama fikirlerinin gelişmesi olarak kırk yıldan fazla bir süre önce ortaya çıktı. Bana göre prosedürel programlamanın ideolojisi özel bir şey değil: tüm programlar bir dizi prosedür ve işlevle temsil edilirken, prosedürler ve işlevlerin kendisi, yürütülmesi bellekteki değişkenlerin değerlerini değiştiren ifade dizileridir. . Prosedürel programlamadaki ana program aynı zamanda, gövdesi diğer prosedürlere ve işlevlere - alt programlara - çağrılar içerebilen bir prosedürdür (işlev). Prosedürel programlamanın özü basittir: veriler ayrıdır, davranışlar ayrıdır. İçinde hangi yapıların yer aldığını ayrı bir bölümde toplamaya çalıştım. Kodu alt rutinlere bölmek öncelikle izin verir ve ikinci olarak izin verir.

Nesneye yönelik programlamanın ideolojisi, adından da anlaşılacağı gibi, nesne kavramı etrafında inşa edilmiştir. Bir nesne hem verileri hem de davranışı birleştirir. Bir nesne, programın ilgilendiği herhangi bir varlıktır; yani: program tarafından modellenen etki alanı nesneleri; işletim sistemi kaynakları; ağ protokolleri ve çok daha fazlası. Özünde bir nesne aynıdır ancak bu yapının öğelerini kontrol eden prosedürler ve işlevlerle desteklenmiştir. Örneğin, prosedürel bir programlama dilinde, dosya adını depolamak için ayrı ayrı ve tanımlayıcısını (işletim sistemindeki benzersiz bir kaynak tanımlayıcısı) ve dosyayla çalışmak için bir dizi prosedürü depolamak için ayrı ayrı bir değişken oluşturulur: dosyayı açın, dosyadaki verileri okuyun ve dosyayı kapatın. Tüm bu prosedürlerde, sonucun saklanmasına yönelik olağan parametrelere ve değişkenlere ek olarak, hangi dosyadan bahsettiğimizi anlamak için aynı tanımlayıcıyı kabul etmek gerekecektir. Nesne yönelimli bir dilde, aynı amaç için, kendi içinde bir ad ve tanıtıcıyı da saklayan ve kullanıcıya kendisini açma, okuma ve kapatma prosedürlerini (belirli bir dosyayla ilişkili dosya) sağlayan bir dosya nesnesi tanımlanır. nesne). Aradaki fark, tanıtıcının programın geri kalanından gizlenmesi, dosya açma rutin kodunda oluşturulması ve yalnızca nesnenin kendisi tarafından dolaylı olarak kullanılmasıdır. Böylece, nesnenin kullanıcısının (nesnenin dışındaki programın program kodu), prosedür parametrelerinde her seferinde tanıtıcıyı geçmesine gerek kalmayacaktır. Bir nesne, uygulama ayrıntılarını da içeren, bazıları etrafındaki dünyadan gizlenmiş olabilecek bir dizi veri ve bu verilerle çalışmaya yönelik yöntemlerdir. Nesneye yönelik programlamanın terminolojisi aşağıda daha ayrıntılı olarak ele alınacaktır.

Nesne yönelimli bir programlama dilinde, ifadeler dışında hemen hemen her şey bir nesnedir: ve nesnelerdir ve hata açıklaması bir nesnedir ve son olarak ana program da bir nesnedir. Programın kendisi açısından bir nesnenin ne olduğunu, nasıl yaratıldığını ve kullanıldığını anlamak için kalır. OOP'un ikinci temel kavramı sınıftır. Sınıf, örneklerine nesne adı verilen prosedürel programlamaya kıyasla yeni bir veri türüdür. Daha önce de belirtildiği gibi bir sınıf, bileşik veri tipine veya yapısına benzer, ancak verileriyle çalışmaya yönelik prosedürler ve işlevler (yöntemler) ile desteklenmiştir. Şimdi nesne yönelimli programlamanın temel terimlerini açıklamanın zamanı geldi.

Nesneye Yönelik Programlama Terminolojisi

OOP'un yazılım geliştiricilere süreç ve yazılım ürünlerinde sağladığı faydaları anlatmaya geçmeden önce bu alanda en sık kullanılan terimlere aşina olmak gerekir.

Sınıf – nesnelerin yapısını ve davranışını tanımlayan bir veri türü.

Bir obje – bir sınıfın örneği.

Alan – sınıf veri öğesi: bir sınıfın parçası olan temel tür, yapı veya başka bir sınıfın değişkeni.

Nesne durumu – geçerli nesne alanı değerlerinin bir kümesi.

Yöntem – çağrıldığı nesnenin bağlamında yürütülen bir prosedür veya işlev. Yöntemler, geçerli nesnenin durumunu veya kendilerine parametre olarak iletilen nesnelerin durumunu değiştirebilir.

Mülk – bir nesnenin bireysel alanlarını değiştirmek için tasarlanmış özel bir yöntem türü. Özelliklerin adları genellikle karşılık gelen alanların adlarıyla aynıdır. Dışarıdan bakıldığında, özelliklerle çalışmak, bir yapının veya sınıfın alanlarıyla çalışmakla tamamen aynı görünür, ancak aslında, bir alana yeni bir değer döndürmeden veya atamadan önce, çeşitli kontrol türlerini gerçekleştiren program kodu çalıştırılabilir, örneğin kontrol etme yeni değerin geçerli olup olmadığı.

Sınıf üyesi – sınıfın alanları, yöntemleri ve özellikleri.

Erişim değiştirici – sınıf üyelerinin, harici bir programdan erişilip erişilemeyeceğini veya yalnızca sınıfın sınırları içinde kullanılıp kullanılmadığını ve dış dünyadan gizlenip gizlenmediğini belirleyen ek bir özelliği. Erişim değiştiricileri, bir sınıfın tüm üyelerini uygulama ayrıntılarına ve genel veya kısmen genel bir arayüze ayırır.

Oluşturucu – bir sınıfın örneğini oluşturduktan hemen sonra yürütülen özel bir yöntem. Yapıcı nesnenin alanlarını başlatır - nesneyi başlangıç ​​durumuna getirir. Yapıcılar parametreli veya parametresiz olabilir. Parametreleri olmayan bir kurucuya, yalnızca bir taneye sahip olabilen varsayılan kurucu denir. Yapıcı yönteminin adı çoğunlukla sınıfın adıyla örtüşür.

Yıkıcı – bir nesnenin RAM'den kaldırıldığı anda program yürütme ortamı tarafından çağrılan özel bir yöntem. Yıkıcı, sınıfın açık yayın gerektiren kaynakları (dosyalar, veritabanı bağlantıları, ağ bağlantıları vb.) içerdiği durumlarda kullanılır.

Arayüz – bir nesnenin kamuya açık olan ve belirli bir dizi sorunu çözmek için tasarlanmış bir dizi yöntem ve özelliği; örneğin, bir nesnenin ekranda grafiksel bir temsilini oluşturmak için bir arayüz veya bir nesnenin durumunu kaydetmek için bir arayüz bir dosyada veya veritabanında.

Statik üye – karşılık gelen bir nesne oluşturulmadan kullanılabilen bir sınıfın herhangi bir öğesi. Örneğin, bir sınıf yöntemi tek bir alan kullanmıyorsa ve yalnızca kendisine iletilen parametrelerle çalışıyorsa, o zaman hiçbir şey onun ayrı örnekleri oluşturulmadan tüm sınıf bağlamında kullanılmasını engellemez. Bir sınıf bağlamındaki sabitler genellikle her zaman sınıfın statik üyeleridir.

Bunların hepsi OOP terminolojisiyle sınırlı değildir ancak bu paradigmayla ilişkili diğer kavramlar bir sonraki bölümde tartışılacaktır.

Nesneye Yönelik Programlamanın Faydaları

Şimdi bir programın tasarımında ve kodlamasında nesne yönelimli bir yaklaşım kullanıldığında edindiği özelliklerden bahsedelim. Bana öyle geliyor ki bu özelliklerin çoğu OOP'un avantajlarıdır, ancak bu konuda başka görüşler de var...

    Kapsülleme bireysel üyeleri uygun erişim değiştiricilerle ödüllendirerek bir sınıfın uygulama ayrıntılarının gizlenmesini ifade eder. Böylece, bir nesnenin diğer program nesneleriyle etkileşimi amaçlayan tüm işlevleri açık bir arayüzde gruplandırılır ve ayrıntılar içeride dikkatlice gizlenir, bu da ana iş mantığı kodunu ihtiyaç duymadığı şeylerden kurtarır. Kapsülleme, belirli verilerin kapsayıcı sınıfın dışında değiştirilememesini sağladığı için kodunuzun güvenilirliğini artırır.

    Miras. OOP'un temel taşı. Nesneye yönelik programlamada bir sınıfın yapısını ve davranışını başka bir sınıftan miras almak mümkündür. Miras aldıkları sınıfa temel veya üst sınıf denir ve kalıtım sonucu elde edilen sınıfa türetilmiş veya basitçe alt sınıf denir. Herhangi bir sınıf hem üst sınıf hem de alt sınıf olarak hareket edebilir. Sınıf miras ilişkileri bir sınıf hiyerarşisi oluşturur. Çoklu kalıtım, aynı anda birden fazla üst sınıftan türetilen bir sınıfın tanımıdır. Nesne yönelimli programlama dillerinin tümü çoklu kalıtımı desteklemez. Kalıtım, yeniden kullanılabilir kod parçalarını ayırmanın etkili bir yoludur ancak daha sonra tartışılacak olan dezavantajları da vardır.

    Soyutlama. Hepsi için önemli olan ortak özellikleri (ortak alanlar ve ortak davranışlar) vurgulayarak sınıfları ayrı gruplar halinde birleştirme yeteneği. Aslında soyutlama kalıtımın bir sonucudur: Temel sınıfların her zaman gerçek dünyanın nesnelerine kendi yansımaları yoktur, yalnızca tüm bir nesne grubunun ortak özelliklerini vurgulamak amacıyla yaratılırlar. Örneğin, bir mobilya nesnesi bir masa, sandalye ve kanepe için temel bir kavramdır, hepsi taşınabilir mülk olmaları, binanın iç kısmının bir parçası olmaları ve bir ev veya ofis için yapılabilmeleri gerçeğiyle birleştirilmiştir. ve ayrıca sınıfa “ekonomi” veya “premium” kelimelerini de kullanın. OOP'ta bunun için ayrı bir kavram vardır: soyut bir sınıf - nesnelerinin yaratılması yasak olan ancak temel sınıf olarak kullanılabilen bir sınıf. Kalıtım ve soyutlama, program veri yapılarını ve bunlar arasındaki ilişkileri, söz konusu sistemdeki ilgili nesnelerle tamamen aynı şekilde tanımlamayı mümkün kılar.

    Mevcut araç tiplerinin analizi sırasında soyutlama yoluyla oluşturulan bir sınıf diyagramının örneği aşağıdaki şekilde gösterilmektedir. Üst seviyelerde miras hiyerarşisi araçları en önemli özelliklerine göre birleştiren soyut sınıflar vardır.


    Sınıf diyagramı veya miras hiyerarşisi "Araçlar". Beyaz kareler soyut sınıfları temsil eder.

    Polimorfizm. Mirasın bir sonucu olan başka bir mülk. Gerçek şu ki, nesne yönelimli programlama dilleri, aynı hiyerarşideki bir dizi nesneyle, sanki hepsi kendi temel sınıflarının nesneleriymiş gibi çalışmanıza olanak tanır. Mobilya ile ilgili örneğe dönersek, bir mobilya mağazası için bilgi sistemi oluşturma bağlamında, tüm mobilya türleri için temel sınıfa ortak bir “özellik gösterme” yönteminin eklenmesinin mantıklı olacağını varsayabiliriz. Program, tüm mal türlerinin özelliklerini yazdırırken, bu yöntemi ayrım gözetmeksizin tüm nesneler için çağıracak ve her belirli nesne, kendisine hangi bilgiyi sağlayacağına kendisi karar verecektir. Bu nasıl uygulanır: Öncelikle temel sınıf, ortak davranışa sahip herkes için ortak bir yöntem tanımlar. Örneğimizde bu tüm mobilya türlerinde ortak olan parametreleri yazdıran bir yöntem olacaktır. İkinci olarak, türetilmiş her sınıfta, gerektiğinde temel yöntemi yeniden tanımlarlar (aynı adda bir yöntem ekleyerek), temel davranışı kendileriyle genişletirler, örneğin yalnızca belirli bir türe özgü olan özellikleri görüntülerler. mobilya ürünü. Temel sınıftaki bir yöntemin bazen hiçbir kod içermesi gerekmez, yalnızca bir adı ve bir dizi parametreyi (yöntemin imzasını) tanımlamak için gereklidir. Bu tür yöntemlere soyut yöntemler denir ve bunları içeren sınıflar otomatik olarak soyut sınıflara dönüşür. Yani polimorfizm, belirli bir arayüz aracılığıyla farklı sınıflardaki nesnelerle aynı şekilde iletişim kurma yeteneğidir. Polimorfizm ideolojisi, bir nesneyle iletişim kurmak için onun türünü bilmenizin gerekmediğini, bunun yerine hangi arayüzü desteklediğini bilmeniz gerektiğini belirtir.

    Arayüz. Bazı programlama dillerinde (C#, Java), arayüz kavramı açıkça tanımlanmıştır; bu yalnızca sınıfın kendisinin genel yöntemleri ve özellikleri değildir. Bu tür diller, kural olarak, çoklu kalıtımı desteklemez ve herhangi bir nesnenin bir temel nesneye sahip olmasına ve herhangi bir sayıda arabirimi uygulamasına izin vererek bunu telafi eder. Yorumlarına göre bir arayüz, yalnızca genel yöntemlerin ve özelliklerin açıklamasını (imzasını) içeren soyut bir sınıf gibidir. Bir arayüzün uygulanması, onu desteklemeyi amaçlayan her sınıfın omuzlarına düşer. Aynı arayüz tamamen farklı hiyerarşilerdeki sınıflar tarafından uygulanabilir, bu da polimorfizm olanaklarını genişletir. Örneğin, "bilgiyi bir veritabanına kaydetme/geri yükleme" arayüzü, hem "mobilya" hiyerarşisinin sınıfları hem de mobilya üretimi için sipariş vermeyle ilişkili sınıflar tarafından uygulanabilir ve "kaydet" düğmesine tıkladığınızda, program tüm nesneleri inceleyecek, onlardan bu arayüzü isteyecek ve karşılık gelen yöntemi çağıracaktır.

Nesne yönelimli programlama sürekli gelişerek görünüş yönelimli, konu yönelimli ve hatta etmen yönelimli programlama gibi yeni paradigmaların ortaya çıkmasına neden oluyor. OOP'un şöhretinin diğer teorisyenleri rahatsız ettiği ve onu geliştirmek ve genişletmek için kendi seçeneklerini sunmak için acele ettikleri belirtilmelidir. Bununla ilgili ayrı bir not yazmıştım ama şimdi JavaScript istemci tarafı dilini uygulayan prototip programlama hakkında birkaç söz söylemek istiyorum. Prototip programlama, sınıf kavramını ortadan kaldırır ve onun yerine bir prototip (bir nesne örneği) koyar. Dolayısıyla prototip odaklı bir dilde nesne türü kavramı yoktur, ancak bir model veya prototip kavramı vardır. PrototipÜyelerinin kopyalanması (klonlanması) yoluyla diğer örneklerin oluşturulduğu bir nesnenin örneğidir. JavaScript'te bir sınıfın alanlarını ve yöntemlerini tanımlamazsınız, ancak önce boş bir nesne oluşturursunuz ve ardından ona gerekli alanları ve yöntemleri eklersiniz (JavaScript'te bir yöntem dinamik olarak tanımlanıp bir nesneye eklenebilir). Aynı şekilde, daha sonra diğer nesneler tarafından prototip olarak anılan prototipler oluşturulur. Bir nesnenin çağrı konumunda belirtilen bir yöntemi veya alanı yoksa, prototipinin üyeleri arasında aranır. Bunu da ayrı ayrı anlattım.

Modern nesne yönelimli programlamanın bazı unsurları

Zaman durmuyor ve OOP'un ortaya çıkışından bu yana oldukça fazla zaman geçti, bu nedenle bugün nesne yönelimli programlamanın kelime dağarcığının önemli ölçüde artması şaşırtıcı olmamalıdır. İşte OOP ile ilgili bazı yeni terim ve kavramlar.

    Olaylar. Bazı nesnelere diğer nesnelerde meydana gelen olaylar hakkında bilgi vermek için oluşturulan özel bir nesne türü. Farklı programlama dillerinde olay mekanizması farklı şekillerde uygulanır: bazen özel sözdizimsel yapılar kullanılarak, bazen de temel OOP araçları kullanılarak.

    Üniversal tip. Jenerik tür kavramı doğrudan OOP kavramıyla ilişkili değildir ancak jenerik sınıf, jenerik yöntem, jenerik olay vb. öğelerin ortaya çıkmasının nedenidir. Genel tür, başka bir tür (tür kümesi) tarafından parametrelendirilen bir türdür. Bu parametre türünün genel tür tasarımı bağlamında ne olduğu bilinmemektedir, ancak parametre türlerinin değerlerini belirli bir sınıftan türetmeye veya belirli arayüzleri uygulamaya zorlayarak kısıtlamak mümkündür. Bir örnek, dizideki öğe türünün önceden bilinmediği bir dizi öğeyi sıralamak için kullanılan evrensel bir sınıftır. Böyle bir sınıf tasarlanırken parametre tipinin karşılaştırma işlemini desteklemesi gerektiğinin belirtilmesi önemlidir. Genel türlerde nesneler oluştururken, tamsayı veya dize türü gibi bir parametreyi açıkça belirtirsiniz ve nesnenin kendisi, tamsayıları veya dizeleri sıralamak için özel olarak oluşturulmuş bir sınıfın örneğiymiş gibi davranmaya başlar.

    İstisnalar. Belirli bir programlama dilinde yerleşik olarak bulunan, hataları ve istisnaları işlemeye yönelik bir mekanizma tarafından desteklenen başka bir özel nesne türü. İstisnalar, hata koduna ek olarak, hata kodunun açıklamasını, olası nedenlerini ve programda istisna oluşmadan önce meydana gelen bir dizi yöntem çağrısını içerir.

Nesne Yönelimli Programlamanın Dezavantajları

Nesneye yönelik yaklaşımın popülaritesinin çok büyük olduğunu daha önce söylemiştim. Ayrıca bu paradigmayı genişletmeye çalışanların oldukça fazla olduğunu da belirtmiştim. Ancak bilgi teknolojisi alanındaki büyük uzmanlar topluluğu arasında öne çıkmanın başka bir yolu daha var - bu, OOP'nin kendisini haklı çıkarmadığını, bunun her derde deva değil, plasebo olduğunu ilan etmektir. Bu insanlar arasında Alexander Stepanov, Edsger Dijkstra ve diğerleri gibi gerçekten çok üst düzey uzmanlar var ve onların görüşleri dikkate değer, ama aynı zamanda hakkında “kötü bir dansçının yoluna her zaman bir şeyler çıkar” dedikleri kişiler de var. ” İşte uzmanların işaret ettiği OOP'un en belirgin dezavantajları:

    OOP, işlevselliğin yayılmasına veya dedikleri gibi sınıfın temel ve türetilmiş üyelerine yayılmasına neden olan devasa sınıf hiyerarşileri üretir ve belirli bir yöntemin işleyiş mantığını izlemenin zorlaşmasına neden olur.

    Bazı dillerde, temel türler de dahil olmak üzere tüm veriler nesnelerdir ve bu, kaçınılmaz olarak ek bellek ve CPU zaman tüketimine yol açar.

    Ayrıca, program yürütme hızı, bir yöntem çağrısının türetilmiş sınıflardan birindeki spesifik uygulamasına geç bağlanmasına yönelik mekanizmalara dayanan polimorfizmin uygulanmasından olumsuz şekilde etkilenebilir.