Soyut Veri Türleri ve nesneler arasındaki fark nedir?


11

Programcılar üzerine bir cevap, Cook tarafından yapılan bir makaleyi ( Nesneler ADT değildir ) şöyle ifade eder:

  • Nesneler, bir cebir yerine bir türün değerleri üzerinde karakteristik bir işlev gibi davranır. Nesneler tip soyutlama yerine prosedürel soyutlama kullanır

  • ADT'lerin genellikle bir programda benzersiz bir uygulaması vardır. Bir kişinin dili modüllere sahip olduğunda, bir ADT'nin birden fazla uygulaması olabilir, ancak genellikle birlikte çalışamazlar.

Bana öyle geliyor ki, Cook'un denemesinde, Cook'un kağıdında kullanılan bir setin spesifik örneği için, bir nesnenin karakteristik bir işlev olarak görülebildiği görülmektedir . Genel olarak nesnelerin karakteristik fonksiyonlar olarak görülebileceğini düşünmüyorum.

Ayrıca, Aldritch'in çalışması Birlikte çalışabilirliğin gücü: Nesneler neden kaçınılmazdır ¹

Cook'un tanımı aslında dinamik dağıtımı nesnenin en önemli özelliği olarak tanımlar

ile kabul Bu dediği zaman ve Alan Kay ile

OOP bana sadece mesajlaşma, yerel tutma ve devlet sürecinin korunması ve gizlenmesi ve her şeyin aşırı geç bağlanması anlamına geliyor.

Bununla birlikte, Aldritch'in makalesindeki bu tamamlayıcı ders slaytları Java sınıflarının ADT'ler olduğunu, Java arayüzlerinin nesneler olduğunu ve gerçekten de "nesnelerin" arayüzlerini kullanabileceğini (yukarıdaki madde işaret noktalarından biri tarafından verilen OOP'un temel özelliklerinden biri) ).

Sorularım

  1. Karakteristik fonksiyonların nesnelerin önemli bir özelliği olmadığını ve Frank Shearar'ın yanıldığını söylemek doğru mudur?

  2. Birbirleriyle Java aracılığıyla konuşan veriler, dinamik dağıtım kullanmasalar bile nesnelerin örneklerini arayüzler mi? Neden? (Anladığım kadarıyla dinamik dağıtım daha esnek ve arayüzler objektif C / smalltalk / erlang tarzı mesajlaşma yolunda bir adım.)

  3. Bağımlılık tersine çevirme fikri ADT'ler ve nesneler arasındaki ayrımla ilgili mi? ( Wikipedia sayfasına veya Konuşan Nesnelere Bakın : Mesaj Odaklı Programlama Hakkında Bir Masal ) Konseptte yeniysem de, bir programın "katmanları" arasına arayüzler eklemeyi içerdiğini anlıyorum (bkz. Wikipedia sayfa diyagramı).

  4. İsterseniz, lütfen nesneler ve ADT'ler arasındaki ayrımın diğer örneklerini / açıklamalarını sağlayın.

¹ (2013 yılında yayınlanmıştır) Bu çalışma kolay okuma ve Java örneklerle Cook'un 2009 kağıdını özetlemektedir. En azından bu soruyu cevaplamamanızı tavsiye ederim, ama sadece iyi bir kağıt olduğu için.


5
İlginç, ancak lütfen kendinizi gönderi başına bir soru ile sınırlamaya çalışın.
Raphael

biraz (ince?) bir akademik ayrım / tartışma gibi görünüyor. görünüşe göre ADT'ler neredeyse java ve diğer modern OOP dillerindeki nesnelerdir. birçok OOP dilinde, soyutlama, nesnelerin gerçek dünyayı modelleme biçimi (kısıtlanmış / odaklanmış bir şekilde) olarak kabul edilir. ayrıca bakınız "soyutlama" tanımı OOP , Yazılım Mühendisliği
vzn

Yanıtlar:


8

Google , çok iyi olduğunu düşündüğüm bir cevapla benzer bir soru getirdi . Aşağıda alıntı yaptım.

Burada bağladığım Cook makalesinde anlatılan başka bir ayrım var.

Soyutlamayı uygulamanın tek yolu nesneler değildir. Her şey bir nesne değildir. Nesneler, bazı kişilerin prosedürel veri soyutlaması olarak adlandırdığı bir şey uygular. Soyut veri türleri farklı bir soyutlama biçimi uygular.

İkili yöntemleri / işlevleri düşündüğünüzde önemli bir fark görünür. Yordamsal veri soyutlama (nesneler) ile, Int set arabirimi için şöyle bir şey yazabilirsiniz:

interface IntSet {
  void unionWith(IntSet s);
  ...
}

Şimdi IntSet'in iki uygulamayı düşünün, diyelim ki listelerle desteklenir, diğeri daha verimli bir ikili ağaç yapısı ile desteklenir:

class ListIntSet implements IntSet {
  void unionWith(IntSet s){ ... }
} 
class BSTIntSet implements IntSet {
  void unionWith(IntSet s){ ... }
}

UnionWith öğesinin bir IntSet argümanı alması gerektiğine dikkat edin. ListIntSet veya BSTIntSet gibi daha belirgin bir tür değil. Bu, BSTIntSet uygulamasının girdisinin bir BSTIntSet olduğunu varsayamayacağı ve bu gerçeği verimli bir uygulama sağlamak için kullanamayacağı anlamına gelir. (Kontrol etmek için bazı çalışma süresi türü bilgileri kullanabilir ve varsa daha verimli bir algoritma kullanabilir, ancak yine de bir ListIntSet'ten geçirilebilir ve daha az verimli bir algoritmaya geri dönmesi gerekir).

Bunu, imza veya başlık dosyasında aşağıdakine benzer bir şey yazabileceğiniz ADT'lerle karşılaştırın:

typedef struct IntSetStruct *IntSetType;
void union(IntSetType s1, IntSetType s2);

Bu arayüze karşı program yapıyoruz. Özellikle, tür soyut bırakılır. Ne olduğunu bilmiyorsun. Daha sonra bir BST uygulamamız var ve daha sonra somut bir tür ve operasyonlar sağlıyor:

struct IntSetStruct {
 int value;
 struct IntSetStruct* left;
 struct IntSetStruct* right;
}

void union(IntSetType s1, IntSetType s2){ ... }

Şimdi sendika aslında hem s1 hem de s2'nin somut temsillerini biliyor, bu yüzden verimli bir uygulama için bundan faydalanabilir. Ayrıca liste destekli bir uygulama yazabilir ve bunun yerine bağlantı kurmayı seçebiliriz.

C (ish) sözdizimi yazdım, ancak düzgün şekilde yapılan soyut veri türleri için örneğin Standart ML'ye bakmalısınız (burada aslında bir programın birden fazla ADT uygulamasını kabaca türleri niteleyerek kullanabilirsiniz: BSTImpl. IntSetStruct ve ListImpl.IntSetStruct, diyelim)

Bunun tersi, prosedürel veri soyutlamasının (nesneler) eskilerinizle çalışan yeni uygulamaları kolayca tanıtmanıza izin vermesidir. örneğin, kendi özel LoggingIntSet uygulamanızı yazabilir ve bir BSTIntSet ile birleştirebilirsiniz. Ama bu bir değiş tokuş: ikili yöntemler için bilgilendirici türleri kaybedersiniz! Genellikle arayüzünüzde bir ADT uygulamasından daha fazla işlevsellik ve uygulama ayrıntısı ortaya çıkarmak zorunda kalırsınız. Şimdi sadece Cook denemesini yeniden yazıyormuşum gibi hissediyorum, gerçekten okuyun!

Buna bir örnek eklemek istiyorum.

Cook, soyut bir veri türünün bir örneğinin C'deki bir modül olduğunu önerir. Aslında, C'deki modüller bilgi gizlemeyi içerir, çünkü bir başlık dosyası yoluyla dışa aktarılan genel işlevler ve olmayan statik (özel) işlevler vardır. Ayrıca, genellikle yapıcılar (örn. List_new ()) ve gözlemciler (ör. List_getListHead ()) vardır.

Diyelim ki, LIST_MODULE_SINGLY_LINKED ADT adlı bir liste modülünün önemli bir noktası, modülün işlevlerinin (örn. List_getListHead ()), girilen verilerin herhangi bir "eşdeğenin aksine LIST_MODULE_SINGLY_LINKED yapıcısı tarafından oluşturulduğunu varsaymasıdır. "bir listenin uygulanması (örn. LIST_MODULE_DYNAMIC_ARRAY). Bu, LIST_MODULE_SINGLY_LINKED işlevlerinin, uygulamalarında belirli bir temsili (örneğin, tek bağlantılı bir liste) varsayabileceği anlamına gelir.

LIST_MODULE_SINGLY_LINKED, LIST_MODULE_DYNAMIC_ARRAY ile LIST_MODULE_DYNAMIC_ARRAY ile etkileşime giremedi, çünkü LIST_MODULE_SINGLY_LINKED yapıcısı ile LIST_MODULE_SINGLY_M_NUMA__SAYAN_BİLGİSİNİ yalnızca bir liste için bir atandı.

Bu, soyut cebirden iki farklı grubun birlikte çalışamayacağı şekle benzer (yani, bir grubun bir öğesinin ürününü başka bir grubun bir öğesiyle alamazsınız). Bunun nedeni, grupların grubun kapanma özelliğini almasıdır (bir gruptaki öğelerin ürünü grupta olmalıdır). Bununla birlikte, iki farklı grubun aslında başka bir G grubunun alt grupları olduğunu kanıtlayabilirsek, G grubunun ürününü, iki grubun her birinden bir tane olmak üzere iki eleman eklemek için kullanabiliriz.

ADT'leri ve nesneleri karşılaştırma

  • Cook, ADT'ler ve nesneler arasındaki farkı kısmen ifade sorununa bağlar. Kabaca söylemek gerekirse, ADT'ler genellikle işlevsel programlama dillerinde uygulanan genel işlevlerle birleştirilirken, nesneler arabirimlerden erişilen Java "nesneleri" ile birleştirilir. Bu metnin amaçları için, genel bir işlev bazı ARGS bağımsız değişkenlerini ve bir TYPE türünü (ön koşul) alan bir işlevdir; TYPE temel alınarak uygun işlevi seçer ve ARGS (post-condition) ile değerlendirir. Hem genel fonksiyonlar hem de nesneler polimorfizm uygular, ancak genel fonksiyonlarda, programcı jenerik fonksiyonun koduna bakmadan jenerik fonksiyon tarafından yürütülecek olan BİLDİRİCİ BİLGİLERİ. Öte yandan nesnelerle, programcılar nesnenin koduna bakmadıkça, programcı nesnenin bağımsız değişkenleri nasıl işleyeceğini bilmez.

  • Genellikle ifade problemi "çok fazla temsilim var mı?" vs. "çok az temsili olan birçok fonksiyonum var" İlk durumda, kod temsili olarak düzenlenmelidir (özellikle Java'da en yaygın olanıdır). İkinci durumda, kod fonksiyonlara göre düzenlenmelidir (yani, tek bir genel fonksiyonun birden fazla temsili ele alması).

  • Kodunuzu temsile göre düzenlerseniz, daha fazla işlevsellik eklemek istiyorsanız, bu işlevi nesnenin her gösterimine eklemek zorunda kalırsınız ; bu anlamda işlevsellik ekleme "katkı maddesi" değildir. Kodunuzu işlevselliğe göre düzenlerseniz, fazladan bir gösterim eklemek istiyorsanız - her nesneye temsili eklemek zorunda kalırsınız ; bu anlamda "katkı maddesi" değil temsiller eklemek.

ADT'lerin nesnelere göre avantajı

  • İşlev eklemek ek bir şeydir

  • Performans için bir ADT'nin temsili bilgisinden faydalanmak veya ADT'nin bir önkoşul verildiğinde bazı son koşulları garanti edeceğini kanıtlamak mümkündür. Bu, ADT'lerle programlamanın doğru şeyleri doğru sırayla yapmakla ilgili olduğu anlamına gelir (önkoşulları ve sonkoşulları "hedef" sonrası koşula doğru birleştirmek).

Nesnelerin ADT'lere göre avantajları

  • Katkı maddesine temsiller ekleme

  • Nesneler etkileşime girebilir

  • Bir nesne için öncesi / sonrası koşullarını belirlemek ve bunları ADT'lerde olduğu gibi birbirine zincirlemek mümkündür. Bu durumda, nesnelerin avantajları, (1) arayüzü değiştirmeden temsillerin değiştirilmesinin kolay olması ve (2) nesnelerin birlikte çalışabilmesidir. Bununla birlikte, bu, OOP'un amacını smalltalk anlamında yener. (bkz. "Alan Kay'ın OOP versiyonu)

Dinamik dağıtım OOP'un anahtarıdır

Şimdi nesneye yönelik programlama için dinamik dağıtımın (yani geç bağlama) gerekli olduğu açıktır. Bu, prosedürleri belirli bir temsili varsaymayan jenerik bir şekilde tanımlamak mümkündür. Python'da somut - nesne yönelimli programlama kolaydır, çünkü bir nesnenin yöntemlerini belirli bir temsili varsaymayacak şekilde programlamak mümkündür. Bu nedenle python'un Java gibi arayüzlere ihtiyacı yoktur.

Java'da sınıflar ADT'lerdir. ancak, uyguladığı arabirimden erişilen bir sınıf bir nesnedir.

Zeyilname: Alan Kay'ın OOP versiyonu

Alan Kay, nesnelere açıkça "cebir familyaları" diye değinmiştir ve Cook, ADT'nin bir cebir olduğunu ileri sürmektedir. Dolayısıyla Kay muhtemelen bir nesnenin bir ADT ailesi olduğu anlamına geliyordu. Yani bir nesne, Java arabirimini karşılayan tüm sınıfların toplanmasıdır.

Ancak Cook tarafından boyanmış nesnelerin resmi Alan Kay'ın vizyonundan çok daha kısıtlayıcı. Nesnelerin bir ağdaki bilgisayarlar veya biyolojik hücreler gibi davranmasını istedi. Fikir, programlamaya en az bağlılık ilkesini uygulamaktı - böylece, yüksek düzey katmanlar kullanılarak kullanılarak bir ADT'nin düşük düzey katmanlarını değiştirmek kolaydır. Bu resim göz önünde bulundurulduğunda, Java arayüzleri çok kısıtlayıcıdır, çünkü bir nesnenin mesajın anlamını yorumlamasına ve hatta tamamen görmezden gelmesine izin vermezler .

Özetle, Kay için nesnelerin ana fikri, onların bir cebir ailesi (Cook tarafından vurgulandığı gibi) oldukları değildir . Bunun yerine, Kay'ın ana fikri, büyük (ağdaki bilgisayarlar) içinde çalışan bir modeli küçük olana (bir programdaki nesneler) uygulamaktı.

edit: Kay'ın OOP sürümünde bir başka açıklama: Nesnelerin amacı, açıklayıcı bir ideale yaklaşmaktır. Nesneye ne yapacağını söylemeliyiz - prosedürel programlama ve ADT'lerde olduğu gibi mikro yönetimin durumunun nasıl olduğunu söylememeliyiz. Burada , burada , burada ve burada daha fazla bilgi bulabilirsiniz .

edit: Alan Kay'ın OOP tanımını burada çok ama çok iyi bir şekilde buldum .


3

ADT destekçilerine bakarsanız, bir ADT'yi OOP'un bir sınıf (içsel, özel durum; sınırlı bir işlem kümesine izin verilir) dediği şey olarak görürler, ancak sınıflar (temel olarak miras yok) dikkate alınmaz. Asıl mesele, aynı davranışın farklı uygulamalarla elde edilebilmesidir. Örneğin, bir küme liste, bir dizideki veya karma tablodaki öğeler veya bir tür ağaç olarak uygulanabilir.


2

Bunu hep böyle anladım:

  1. Bir ADT bir arabirimdir: sadece yöntemlerin bir koleksiyonudur, tip imzaları, muhtemelen öncesi ve sonrası koşullarıyla.

  2. A sınıfı olabilir uygulamak ADT belirtilen yöntemler için gerçek uygulamaları vererek, bir veya daha fazla soyut veri tiplerini.

  3. Nesne, statik olmayan değişkenlerin kendi kopyasına sahip bir sınıf örneğidir .

Literatürde, ayrımların farklı olması mümkündür, ancak bu bilgisayar biliminde duyacağınız "standart" terminolojidir.

Örneğin, Java'da Collectionbir ADT, ArrayListbir sınıftır ve işleçle bir ArrayListnesne oluşturabilirsiniz new.

ADT'lerin genellikle sadece bir uygulaması olduğu açıklamasına gelince, durum genellikle böyle değildir. Örneğin, ne sakladığınıza bağlı olarak, programınızda hem ağaç hem de karma tabanlı sözlükler kullanmak isteyebilirsiniz. Bir ADT'yi paylaşırlar, ancak farklı uygulamalar kullanırlardı.


1
İşlevsel bir programlama perspektifinden bakıldığında, ADT'lerin genel olarak sınıfların sahip olmadığı bazı kısıtlamaları yoktur?
Raphael

@Raphael Ne gibi?
jmite

1
Bu, ADT'lerin ortak bir görüşüdür ve makul bir yaklaşımdır. Ancak, anladığım kadarıyla PL literatüründe ele alınan ve resmi olarak tanımlandığı gibi ADT'lerin aslında biraz daha spesifik bir anlamı vardır. ADT, bir tür veri yapısının spesifikasyonudur: nasıl uygulandığı veya verilerin nasıl temsil edildiği değil, bunun arayüzü (ne tür işlemler gerçekleştirilebilir?) Ve bu işlemlerin her birinin davranışı / semantiği. Bu yüzden sadece bir Java arayüzü (tip imzaları olan yöntemlerin bir listesi) değil, aynı zamanda davranışlarının bir spesifikasyonu da.
DW

1
Örneğin, benim izlenimim Java Collectionarayüzünün bir ADT olmadığıdır. Yöntemlerin bir listesini sağlar, ancak anlambilimlerini belirtmez. Bir kümenin anlambilimini sağlıyor mu? multiset (çanta)? sıralı bir liste? Bu belirtilmemiş. Bu yüzden bir ADT olarak sayıldığından emin değilim. Bu benim izlenimim, ama anlayışımın yanlış olabilmesi tamamen mümkün ...
DW

Bağlandığım ders slaytlarında, bir Java sınıfı (bir arabirim bile değil!) Bir ADT olarak kabul edilir, çünkü bir sınıfın hem özel hem de genel bölümleri vardır (sınıfın bir kısmının gayri resmi olarak belirtileceğini ancak emin değilim) . Öte yandan, bir arabirimden erişilen bir sınıf, arabirim tarafından tanımlanan yöntemlerin "iletiler" (üst düzey niyetler) olduğu bir nesne olarak kabul edilir. Nesneler niyetlerle birbirleriyle konuştuğunda, bir nesnenin farklı uygulamaları birbiriyle "konuşabilir".
LMZ
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.