Apa perbedaan antara Jenis dan objek Data Abstrak?

11

Sebuah jawaban pada Programmers.SE ciri esai oleh Masak ( Objects tidak ADT ) yang mengatakan

  • Objek berperilaku seperti fungsi karakteristik atas nilai-nilai tipe, bukan sebagai aljabar. Objek menggunakan abstraksi prosedural daripada jenis abstraksi

  • ADT biasanya memiliki implementasi unik dalam suatu program. Ketika bahasa seseorang memiliki modul, ada kemungkinan untuk memiliki beberapa implementasi ADT, tetapi mereka biasanya tidak dapat beroperasi.

Tampak bagi saya bahwa, dalam esai Cook, kebetulan bahwa untuk contoh spesifik dari set yang digunakan dalam kertas Cook, objek dapat dilihat sebagai fungsi karakteristik . Saya tidak berpikir objek itu, secara umum dapat dilihat sebagai fungsi karakteristik.

Juga, kertas Aldritch . Kekuatan interoperabilitas: Mengapa objek tidak dapat dihindari ¹ menyarankan

Definisi Cook pada dasarnya mengidentifikasi pengiriman dinamis sebagai karakteristik paling penting dari objek

setuju dengan ini dan dengan Alan Kay ketika dia berkata

OOP bagi saya hanya berarti pengiriman pesan, penyimpanan dan perlindungan lokal dan menyembunyikan proses negara, dan sangat mengikat semua hal.

Namun, kuliah pendamping ini slide ke kertas Aldritch menyarankan bahwa kelas Java adalah ADT sedangkan antarmuka Java adalah objek - dan memang menggunakan antarmuka "objek" dapat saling beroperasi (salah satu fitur utama OOP seperti yang diberikan oleh salah satu poin di atas) ).

Pertanyaan saya adalah

  1. Apakah saya benar mengatakan bahwa fungsi karakteristik bukan fitur kunci dari objek dan bahwa Frank Shearar salah?

  2. Apakah data yang berbicara satu sama lain melalui antarmuka Java contoh objek meskipun mereka tidak menggunakan pengiriman dinamis? Mengapa? (Pemahaman saya adalah bahwa pengiriman dinamis lebih fleksibel, dan antarmuka adalah langkah menuju obyektif-C / smalltalk / gaya pesan erlang.)

  3. Apakah gagasan prinsip inversi ketergantungan terkait dengan perbedaan antara ADT dan objek? (Lihat halaman Wikipedia atau The Talking Objects: A Tale About Message-Oriented Programming ) Meskipun saya baru mengenal konsep ini, saya mengerti bahwa itu melibatkan penambahan antarmuka antara "lapisan" suatu program (lihat diagram halaman wikipedia).

  4. Harap berikan contoh / klarifikasi lain tentang perbedaan antara objek dan ADT, jika Anda mau.

¹ Makalah ini (diterbitkan pada 2013) mudah dibaca dan merangkum makalah Cook 2009 dengan contoh-contoh di Jawa. Saya sangat merekomendasikan setidaknya membaca sekilas, bukan untuk menjawab pertanyaan ini, tetapi hanya karena itu makalah yang bagus.

LMZ
sumber
5
Menarik, tetapi harap coba batasi diri Anda pada satu pertanyaan per posting.
Raphael
tampaknya agak merupakan perbedaan / debat akademik (halus?). rupanya ADT hampir objek misalnya di java & bahasa OOP modern lainnya. dalam banyak bahasa OOP, abstraksi dianggap sebagai cara benda memodelkan (dengan cara terbatas / terfokus) dunia nyata. lihat juga bingung tentang definisi "abstraksi" dalam OOP , Rekayasa Perangkat Lunak
vzn

Jawaban:

8

Google mengajukan pertanyaan serupa dengan jawaban yang menurut saya sangat bagus. Saya kutip di bawah ini.

Ada perbedaan lain yang mengintai di sini yang dijelaskan dalam esai Cook yang saya tautkan.

Objek bukan satu-satunya cara untuk mengimplementasikan abstraksi. Tidak semuanya adalah objek. Objek mengimplementasikan sesuatu yang oleh sebagian orang disebut abstraksi data prosedural. Tipe data abstrak menerapkan bentuk abstraksi yang berbeda.

Perbedaan utama muncul ketika Anda mempertimbangkan metode / fungsi biner. Dengan abstraksi data prosedural (objek), Anda dapat menulis sesuatu seperti ini untuk antarmuka set Int:

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

Sekarang pertimbangkan dua implementasi IntSet, katakanlah yang didukung oleh daftar dan yang didukung oleh struktur pohon biner yang lebih efisien:

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

Perhatikan bahwa unionWith harus mengambil argumen IntSet. Bukan tipe yang lebih spesifik seperti ListIntSet atau BSTIntSet. Ini berarti bahwa implementasi BSTIntSet tidak dapat mengasumsikan bahwa inputnya adalah BSTIntSet dan menggunakan fakta tersebut untuk memberikan implementasi yang efisien. (Itu bisa menggunakan beberapa informasi tipe waktu berjalan untuk memeriksanya dan menggunakan algoritma yang lebih efisien jika ya, tetapi masih bisa dilewatkan ListIntSet dan harus kembali ke algoritma yang kurang efisien).

Bandingkan ini dengan ADT, tempat Anda dapat menulis sesuatu yang lebih seperti yang berikut ini di file tanda tangan atau header:

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

Kami memprogram melawan antarmuka ini. Khususnya, tipe ini dibiarkan abstrak. Anda tidak tahu apa itu. Kemudian kami memiliki implementasi BST kemudian memberikan jenis konkret dan operasi:

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

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

Sekarang union sebenarnya mengetahui representasi konkrit dari kedua s1 dan s2, sehingga dapat memanfaatkan ini untuk implementasi yang efisien. Kami juga dapat menulis implementasi yang didukung daftar dan memilih untuk menautkannya.

Saya telah menulis sintaks C (ish), tetapi Anda harus melihat misalnya Standar ML untuk tipe data abstrak yang dilakukan dengan benar (di mana Anda dapat misalnya menggunakan lebih dari satu implementasi ADT dalam program yang sama secara kasar dengan mengklasifikasikan jenis-jenis: BSTImpl. IntSetStruct dan ListImpl.IntSetStruct, katakanlah)

Kebalikan dari ini adalah bahwa abstraksi data prosedural (objek) memungkinkan Anda untuk dengan mudah memperkenalkan implementasi baru yang bekerja dengan yang lama. mis. Anda dapat menulis implementasi LoggingIntSet kustom Anda sendiri, dan menyatukannya dengan BSTIntSet. Tapi ini adalah kompromi: Anda kehilangan tipe informatif untuk metode biner! Seringkali Anda akhirnya harus mengekspos lebih banyak fungsionalitas dan detail implementasi di antarmuka Anda daripada yang Anda lakukan dengan implementasi ADT. Sekarang saya merasa seperti saya mengetik ulang esai Cook, jadi sungguh, bacalah!

Saya ingin menambahkan contoh untuk ini.

Cook menyarankan bahwa contoh tipe data abstrak adalah modul dalam C. Memang, modul dalam C melibatkan penyembunyian informasi, karena ada fungsi publik yang diekspor melalui file header, dan fungsi statis (pribadi) yang tidak. Selain itu, sering ada konstruktor (mis. List_new ()) dan pengamat (mis. List_getListHead ()).

Poin kunci dari apa yang membuat, misalnya, modul daftar bernama LIST_MODULE_SINGLY_LINKED ADT adalah bahwa fungsi-fungsi modul (mis. List_getListHead ()) mengasumsikan bahwa input data yang dibuat telah dibuat oleh konstruktor LIST_MODULE_SINGLY_LINKED, sebagai kebalikan dari apa pun "setara" "implementasi daftar (mis. LIST_MODULE_DYNAMIC_ARRAY). Ini berarti bahwa fungsi LIST_MODULE_SINGLY_LINKED dapat mengasumsikan, dalam implementasinya, representasi tertentu (misalnya daftar yang ditautkan sendiri).

LIST_MODULE_SINGLY_LINKED tidak dapat berinteraksi dengan LIST_MODULE_DYNAMIC_ARRAY karena kami tidak dapat memberi makan data yang dibuat, katakanlah dengan konstruktor LIST_MODULE_DYNAMIC_ARRAY, kepada pengamat LIST_MODULE_SINGLY_LINKED karena menganggap LIST_ menganggap sebuah asumsi sebagai sebuah perilaku yang dianggap sebagai suatu asumsi, karena menganggap LIST_ sebagai asumsi untuk menganggap sebuah asumsi sebagai sebuah asumsi (hanya anggapan sebagai suatu anggapan) untuk menganggap sebuah asumsi sebagai suatu anggapan yang dianggap sebagai suatu anggapan).

Ini analog dengan cara dua kelompok berbeda dari aljabar abstrak tidak dapat beroperasi (yaitu, Anda tidak dapat mengambil produk dari elemen dari satu grup dengan elemen dari grup lain). Ini karena grup mengasumsikan properti penutupan grup (produk elemen dalam grup harus dalam grup). Namun, jika kita dapat membuktikan bahwa dua grup berbeda sebenarnya adalah subkelompok dari grup G lain, maka kita dapat menggunakan produk G untuk menambahkan dua elemen, satu dari masing-masing dua grup.

Membandingkan ADT dan objek

  • Cook mengikat perbedaan antara ADT dan objek sebagian dengan masalah ekspresi. Secara kasar, ADT digabungkan dengan fungsi generik yang sering diimplementasikan dalam bahasa pemrograman fungsional, sementara objek digabungkan dengan Java "objek" yang diakses melalui antarmuka. Untuk keperluan teks ini, fungsi generik adalah fungsi yang mengambil argumen ARGS dan tipe TYPE (pra-kondisi); berdasarkan TYPE itu memilih fungsi yang sesuai, dan mengevaluasinya dengan ARGS (pasca-kondisi). Baik fungsi generik dan objek menerapkan polimorfisme, tetapi dengan fungsi generik, programmer TAHU fungsi yang akan dieksekusi oleh fungsi generik tanpa melihat kode fungsi generik. Dengan objek di sisi lain, programmer tidak tahu bagaimana objek akan menangani argumen, kecuali jika programmer melihat kode objek.

  • Biasanya masalah ekspresi dipikirkan dalam istilah "apakah saya punya banyak representasi?" vs. "apakah saya memiliki banyak fungsi dengan sedikit representasi". Dalam kasus pertama seseorang harus mengatur kode dengan representasi (seperti yang paling umum, terutama di Jawa). Dalam kasus kedua seseorang harus mengatur kode berdasarkan fungsi (yaitu memiliki fungsi generik tunggal yang menangani banyak representasi).

  • Jika Anda mengatur kode Anda dengan representasi, maka, jika Anda ingin menambahkan fungsionalitas tambahan, Anda dipaksa untuk menambahkan fungsionalitas ke setiap representasi objek; dalam hal ini menambahkan fungsionalitas bukanlah "aditif". Jika Anda mengatur kode Anda berdasarkan fungsionalitas, maka, jika Anda ingin menambahkan representasi tambahan - Anda dipaksa untuk menambahkan representasi ke setiap objek; dalam hal ini menambahkan representasi dalam bukan "aditif".

Keuntungan ADT dibanding objek

  • Menambahkan fungsionalitas adalah tambahan

  • Dimungkinkan untuk meningkatkan pengetahuan tentang representasi ADT untuk kinerja, atau untuk membuktikan bahwa ADT akan menjamin beberapa postcondition diberikan prasyarat. Ini berarti bahwa pemrograman dengan ADT adalah tentang melakukan hal-hal yang benar dalam urutan yang benar (merangkai bersama prasyarat dan prasyarat menuju kondisi pos "tujuan").

Keuntungan objek lebih dari ADT

  • Menambahkan representasi dalam aditif

  • Objek dapat saling beroperasi

  • Dimungkinkan untuk menentukan kondisi sebelum / sesudah suatu objek, dan rantai ini bersama-sama seperti halnya dengan ADT. Dalam hal ini, kelebihan objek adalah (1) mudah untuk mengubah representasi tanpa mengubah antarmuka dan (2) objek dapat saling beroperasi. Namun, ini mengalahkan tujuan OOP dalam arti smalltalk. (lihat bagian "Versi Alan Kay dari OOP)

Pengiriman dinamis adalah kunci untuk OOP

Seharusnya jelas sekarang bahwa pengiriman dinamis (yaitu keterlambatan mengikat) sangat penting untuk pemrograman berorientasi objek. Ini dimaksudkan untuk mendefinisikan prosedur dengan cara yang umum, yang tidak mengasumsikan representasi tertentu. Untuk menjadi konkret - pemrograman berorientasi objek mudah dalam python, karena dimungkinkan untuk memprogram metode objek dengan cara yang tidak menganggap representasi tertentu. Inilah sebabnya mengapa python tidak membutuhkan antarmuka seperti Java.

Di Jawa, kelas adalah ADT. Namun, kelas yang diakses melalui antarmuka yang diimplementasikannya adalah objek.

Tambahan: versi Alan Kay dari OOP

Alan Kay secara eksplisit menyebut objek sebagai "keluarga aljabar", dan Cook menyarankan bahwa ADT adalah aljabar. Karenanya Kay kemungkinan berarti bahwa objek adalah keluarga ADT. Artinya, objek adalah kumpulan semua kelas yang memenuhi antarmuka Java.

Namun, gambar objek yang dilukis oleh Cook jauh lebih ketat daripada visi Alan Kay. Dia ingin benda berperilaku sebagai komputer dalam jaringan, atau sebagai sel biologis. Idenya adalah untuk menerapkan prinsip komitmen paling rendah untuk pemrograman - sehingga mudah untuk mengubah lapisan tingkat rendah dari ADT begitu lapisan tingkat tinggi telah dibangun menggunakannya. Dengan mengingat gambar ini, antarmuka Java terlalu ketat karena mereka tidak mengizinkan objek untuk menafsirkan makna pesan , atau bahkan mengabaikannya sama sekali.

Singkatnya, ide kunci objek, untuk Kay - bukanlah bahwa mereka adalah keluarga aljabar (seperti yang ditekankan oleh Cook). Sebaliknya, ide kunci Kay adalah menerapkan model yang bekerja di besar (komputer dalam jaringan) ke kecil (objek dalam suatu program).

sunting: Klarifikasi lain pada versi Kay OOP: Tujuan objek adalah untuk bergerak lebih dekat ke ideal deklaratif. Kita harus memberi tahu objek apa yang harus dilakukan - tidak memberi tahu bagaimana dengan pengelolaan mikro adalah keadaan, seperti kebiasaan dengan pemrograman prosedural dan ADT. Info lebih lanjut dapat ditemukan di sini , di sini , di sini , dan di sini .

sunting: Saya menemukan eksposisi yang sangat, sangat bagus dari definisi Alan Kay tentang OOP di sini .

LMZ
sumber
3

Jika Anda melihat para pendukung ADT, mereka menganggap ADT sebagai apa yang oleh OOP disebut kelas (internal, negara swasta; serangkaian operasi terbatas diizinkan), tetapi tidak ada hubungan antara kelas (pada dasarnya tidak ada warisan, pada dasarnya) dipertimbangkan. Intinya adalah bahwa perilaku yang sama dapat diperoleh dengan implementasi yang berbeda. Misalnya set dapat diimplementasikan sebagai daftar, elemen dalam array atau hashtable, atau semacam pohon.

vonbrand
sumber
2

Saya selalu memahaminya seperti ini:

  1. ADT adalah antarmuka: itu hanya kumpulan metode, tipe-tanda tangannya, mungkin dengan kondisi pra-dan-pos.

  2. Kelas dapat mengimplementasikan satu atau lebih ADT, dengan memberikan implementasi aktual untuk metode yang ditentukan dalam ADT.

  3. Objek adalah turunan dari kelas, dengan salinannya sendiri dari variabel non-statis.

Mungkin saja dalam literatur, perbedaannya berbeda, tetapi ini adalah terminologi "standar" yang akan Anda dengar dalam ilmu komputer.

Misalnya, di Jawa, Collectionadalah ADT, ArrayListadalah kelas, dan Anda dapat membuat ArrayListobjek dengan newoperator.

Adapun pernyataan bahwa ADT biasanya hanya memiliki satu implementasi, ini sering tidak terjadi. Misalnya, Anda mungkin ingin menggunakan kamus berbasis-pohon dan berbasis-hashtabel dalam program Anda, tergantung pada apa yang Anda simpan. Mereka akan berbagi ADT, tetapi akan menggunakan implementasi yang berbeda.

Ya ampun
sumber
1
Dari perspektif pemrograman fungsional, bukankah ADT memiliki batasan tertentu yang tidak dimiliki oleh kelas pada umumnya?
Raphael
@ Raphael Seperti apa?
jmite
1
Ini adalah pandangan umum dari ADT, dan ini merupakan perkiraan yang masuk akal. Namun, seperti yang saya pahami, ADT seperti yang dipertimbangkan dalam literatur PL dan sebagaimana didefinisikan secara formal sebenarnya memiliki makna yang agak lebih spesifik. ADT adalah spesifikasi dari jenis struktur data: bukan bagaimana itu diterapkan atau bagaimana data diwakili, tetapi antarmuka untuk itu (jenis operasi apa yang dapat dilakukan?) Dan perilaku / semantik dari masing-masing operasi tersebut. Jadi bukan hanya antarmuka Java (daftar metode dengan tipe-tanda tangan), tetapi juga spesifikasi perilaku mereka.
DW
1
Sebagai contoh, kesan saya adalah bahwa Collectionantarmuka Java bukan ADT. Ini memberikan daftar metode tetapi tidak menentukan semantiknya. Apakah itu memberikan semantik satu set? multiset (tas)? daftar yang dipesan? Itu tidak ditentukan. Jadi saya tidak yakin itu dianggap sebagai ADT. Itu kesan saya, tetapi sangat mungkin bahwa pemahaman saya bisa salah ...
DW
Dalam slide kuliah yang saya tautkan, kelas Java (bahkan bukan antarmuka!) Dianggap sebagai ADT, karena kelas memiliki bagian privat dan publik (saya berasumsi bagian dari kelas akan ditentukan secara informal tetapi saya tidak yakin) . Di sisi lain, kelas yang diakses melalui antarmuka dianggap sebagai objek, dengan metode yang didefinisikan oleh antarmuka sebagai "pesan" (niat tingkat tinggi). Ketika objek berbicara satu sama lain melalui niat, implementasi yang berbeda dari suatu objek dapat "berbicara" satu sama lain.
LMZ