Objek versus Struktur Data

Dalam artikel tersebut, terjemahan yang diusulkan di bawah ini, Robert Martin tampaknya mulai dengan pemikiran yang sangat mirip dengan yang dapat dilihat dalam diskusi Yegor Bugaenko tentang ORM, tetapi yang lain menarik kesimpulan. Secara pribadi, pendekatan Yegor membuat saya terkesan, tetapi saya pikir Martin mengungkapkan topik itu lebih terinci. Sepertinya saya perlu berkenalan dengan semua orang yang pernah berpikir tentang tempat ORM mana yang harus diambil dan secara umum, mengapa kita membutuhkan objek di mana semua bidang terbuka. Artikel ini ditulis dalam genre "Dialog", di mana seorang programmer yang lebih berpengalaman membahas masalah dengan seseorang yang kurang berpengalaman.


Apa itu kelas?

Kelas adalah spesifikasi dari banyak objek serupa.


Apa itu objek?

Objek adalah serangkaian fungsi yang melakukan tindakan dengan data yang dienkapsulasi.


Atau lebih baik mengatakan bahwa objek adalah serangkaian fungsi yang melakukan tindakan dengan data yang keberadaannya tersirat

Dalam arti "tersirat"?


Setelah objek memiliki fungsi, dapat diasumsikan bahwa ada juga data di sana, tetapi tidak ada akses langsung ke data dan mereka tidak terlihat sama sekali dari luar.

Bukankah data dalam objek?


Mungkin memang begitu, tetapi aturan yang mengatakan bahwa mereka harus ada adalah tidak. Dari sudut pandang pengguna, suatu objek tidak lebih dari sekumpulan fungsi. Data yang berfungsi dengan fungsi ini harus ada, tetapi posisi data ini tidak diketahui pengguna.

Baiklah, katakan saja.


Nah, apa itu struktur data?

Struktur data adalah kumpulan item terkait.


Atau, dengan kata lain, struktur data adalah seperangkat elemen yang berfungsi berfungsi, keberadaannya tersirat secara implisit.

Baik, baik. Saya mengerti. Fungsi yang bekerja dengan struktur data tidak didefinisikan di dalam struktur ini, tetapi dari keberadaan struktur data kita dapat menyimpulkan bahwa pasti ada sesuatu yang bekerja dengannya.


Benar Dan bagaimana dengan dua definisi ini?

Dalam arti tertentu, mereka saling bertentangan.


Sungguh. Mereka saling melengkapi. Seperti tangan dan sarung tangan.
  • Objek adalah seperangkat fungsi yang bekerja dengan elemen data yang keberadaannya tersirat secara implisit.
  • Struktur data adalah sekumpulan elemen data yang fungsinya berfungsi, keberadaannya tersirat secara implisit.

Wow! Jadi ternyata objek dan struktur data bukan hal yang sama!


Benar Struktur data adalah DTO.

Dan tabel dalam database juga bukan objek, kan?


Benar lagi. Database berisi struktur data, bukan objek.

Tunggu sebentar. Bukankah ORM memetakan tabel dari database ke objek?


Tentu saja tidak. Anda tidak bisa memetakan tabel database ke objek. Tabel dalam database adalah struktur data, bukan objek.

Lalu apa yang dilakukan ORM?


Mereka mentransfer data dari satu struktur ke struktur lainnya.

Jadi mereka tidak ada hubungannya dengan Objects?


Tidak ada sama sekali. Sebenarnya, hal seperti ORM dalam arti teknologi yang memetakan data relasional ke objek tidak ada, karena tabel tidak dapat dipetakan dari database ke objek.

Tetapi mereka mengatakan kepada saya bahwa ORM mengumpulkan objek bisnis.


Tidak, ORM mengambil data dari database yang bekerja dengan objek bisnis

Tapi bukankah struktur data ini jatuh ke dalam objek bisnis?


Mungkin mereka mengerti, atau mungkin juga tidak. ORM tidak tahu apa-apa tentang ini.

Tetapi perbedaannya adalah murni semantik.


Tidak, tidak Ada konsekuensi yang jauh jangkauannya.

Misalnya?


Misalnya, desain skema database dan desain objek bisnis. Objek bisnis menentukan perilaku bisnis. Skema basis data mendefinisikan struktur data bisnis. Struktur ini dibatasi oleh kekuatan yang sangat berbeda. Struktur data bisnis belum tentu merupakan struktur terbaik untuk perilaku bisnis.

Eeee. Ini tidak bisa dipahami.


Pikirkan seperti itu. Skema data tidak dirancang untuk satu aplikasi tunggal, ini dimaksudkan untuk digunakan di seluruh perusahaan. Oleh karena itu, struktur data adalah kompromi antara beberapa aplikasi yang berbeda.

Ini bisa dimengerti.


Bagus Sekarang pikirkan setiap aplikasi. Model objek dari setiap aplikasi menjelaskan bagaimana perilaku aplikasi terstruktur. Setiap aplikasi akan memiliki model objeknya sendiri agar lebih sesuai dengan perilaku aplikasi.

Ahh, begitu. Karena skema data adalah kompromi antara aplikasi yang berbeda, skema tersebut tidak akan jatuh pada model objek dari setiap aplikasi individual.


Benar! Objek dan Struktur terbatas pada hal-hal yang berbeda. Mereka sangat jarang cocok bersama. Orang-orang menyebut ini ketidakcocokan impedansi objek-relasional.

Sesuatu yang saya ingat. Tetapi tampaknya ketidakcocokan impedansi baru saja diperbaiki menggunakan ORM.


Dan sekarang Anda tahu bahwa ini tidak benar. Ketidakcocokan impedansi antara objek dan struktur data saling melengkapi, bukan isomorfik.

Apa?


Mereka bertolak belakang, bukan sesuatu yang serupa.

Berlawanan?


Ya, dalam arti yang sangat menarik. Anda lihat, objek dan struktur data menyiratkan struktur kontrol yang berlawanan secara diametral.

Apa?


Pikirkan seperangkat kelas yang mengimplementasikan beberapa jenis antarmuka umum. Misalnya, bayangkan kelas yang mewakili angka dua dimensi, di mana ada fungsi untuk menghitung luas dan keliling gambar.

Berapa banyak bentuk mendorong kode dengan objek dalam semua contoh?


Mari kita lihat dua jenis bentuk: Kotak dan Lingkaran. Jelas bahwa fungsi untuk menghitung luas dan keliling kelas-kelas ini menggunakan struktur data yang berbeda. Juga dipahami bahwa operasi ini dipanggil menggunakan polimorfisme dinamis.

Tolong pelan-pelan, tidak ada yang jelas.


Ada dua fungsi berbeda untuk menghitung area, satu untuk Square, yang lain untuk Circle. Ketika suatu fungsi dipanggil untuk menghitung area objek tertentu, objek inilah yang memutuskan fungsi mana yang akan dipanggil. Ini disebut polimorfisme dinamis.

Baiklah Tentu saja Suatu objek tahu bagaimana metodenya diimplementasikan. Secara alami.


Sekarang mari kita ubah objek-objek ini menjadi struktur data. Kami menggunakan Serikat yang Didiskriminasi.

Didiskriminasi apa?


Serikat yang Didiskriminasi. Nah, C ++, pointer, kata kunci serikat, bendera untuk menentukan jenis struktur, Serikat Diskriminasi. Dalam kasus kami, ini hanya dua struktur data yang berbeda. Satu untuk Square dan satu untuk Circle. Lingkaran memiliki titik pusat dan jari-jari. Dan kode jenis dari mana dapat dipahami bahwa itu adalah Lingkaran.

Kolom dengan kode akan enum?


Ya benar. Dan Square akan memiliki titik kiri atas dan panjang sisi. Dan juga enum untuk menunjukkan jenisnya.

Baiklah Akan ada dua struktur dengan kode jenis.


Benar Sekarang mari kita lihat fungsi untuk area tersebut. Mungkin akan ada saklar, kan?

Baik. Tentu saja untuk dua kelas. Cabang untuk Alun-alun dan untuk Lingkaran. Dan untuk perimeter, Anda juga membutuhkan sakelar yang serupa.


Dan lagi, benar. Sekarang pikirkan dua skenario ini. Dalam skenario dengan objek, dua implementasi fungsi untuk suatu area independen satu sama lain dan termasuk (dalam arti tertentu) langsung ke tipe. Fungsi untuk area Square adalah milik Square, dan fungsi untuk menentukan area Circle adalah milik Circle.

Oke, saya mengerti apa yang Anda tuju. Dalam skenario dengan struktur data, kedua implementasi fungsi untuk area berada dalam fungsi yang sama, mereka tidak "milik" (apa pun kata itu berarti) untuk tipe.


Lebih jauh lebih baik. Dalam hal objek, jika Anda perlu menambahkan tipe Segitiga, kode apa yang harus diubah?

Jangan mengubah apa pun. Buat saja kelas Segitiga baru. Meskipun tidak, Anda mungkin perlu memperbaiki kode yang membuat objek.


Benar Jadi, saat menambahkan tipe baru, perubahannya dapat diabaikan. Sekarang anggaplah Anda perlu menambahkan fungsi baru - misalnya, fungsi untuk menentukan pusat.

Maka Anda harus menambahkannya ke ketiga jenis, Lingkaran, Kotak dan Segitiga.


Bagus Ternyata menambahkan fungsi baru itu sulit, karena Anda harus membuat perubahan di setiap kelas.

Tetapi dengan struktur data, semuanya berbeda. Untuk menambahkan Segitiga, Anda harus mengubah setiap fungsi untuk menambahkan cabang untuk menangani Segitiga di setiap sakelar.


Benar Sulit untuk menambahkan tipe, Anda harus mengedit setiap fungsi.

Tetapi untuk menambahkan fungsi untuk pusat, tidak ada yang perlu diubah.


Ya, menambahkan fitur itu mudah.

Wow Ternyata kedua pendekatan ini bertolak belakang.


Jelas ya. Untuk meringkas

  • Sulit untuk menambahkan fungsi baru ke kelas, Anda harus membuat perubahan di setiap kelas
  • Menambahkan fungsi baru ke struktur data sederhana, Anda hanya perlu menambahkan fungsi, tidak ada lagi yang perlu diubah
  • Menambahkan tipe baru ke kelas itu sederhana, Anda hanya perlu menambahkan kelas baru
  • Sulit untuk menambahkan tipe baru untuk struktur, Anda perlu memperbaiki setiap fungsi

Ya Berlawanan. Berlawanan dengan rasa ingin tahu. Artinya, jika diketahui sebelumnya bahwa fungsi baru perlu ditambahkan, akan lebih mudah untuk menggunakan struktur data. Tetapi jika Anda tahu sebelumnya bahwa Anda harus menambahkan tipe baru, maka Anda perlu menggunakan kelas.


Pengamatan yang bagus! Tetapi hari ini kita perlu memikirkan satu hal lagi. Ada titik lain di mana struktur data dan kelas saling bertentangan. Ketergantungan.

Kecanduan?


Ya, arah dependensi dalam kode sumber.

Oke, saya akan bertanya. Apa bedanya?


Mari kita lihat kasus struktur. Setiap fungsi berisi sakelar yang memilih implementasi yang diinginkan berdasarkan pada kode jenis dalam gabungan.

Ya, benar. Jadi apa


Mari kita lihat fungsi panggil untuk area tersebut. Kode panggilan tergantung pada fungsi untuk area tersebut, dan fungsi untuk area tersebut tergantung pada setiap implementasi spesifik.

Dan apa yang Anda maksud ketika Anda mengatakan "tergantung"?


Bayangkan bahwa setiap implementasi fungsi untuk area dialokasikan ke fungsi yang terpisah. Artinya, akan ada fungsi circleArea, squareArea dan triangleArea.

Nah, ternyata di cabang switch hanya akan ada panggilan ke fungsi-fungsi ini.


Bayangkan bahwa fungsi-fungsi ini ada di file yang berbeda.

Kemudian dalam file dengan saklar akan diimpor atau digunakan atau disertakan untuk file dengan fungsi.


Benar Ini adalah ketergantungan pada level kode sumber. Satu sumber tergantung pada sumber lain. Bagaimana ketergantungan ini diarahkan?

Kode sumber dengan sakelar bergantung pada kode sumber tempat implementasi.


Bagaimana dengan kode yang memanggil fungsi untuk area tersebut?

Kode panggilan tergantung pada kode dengan saklar, yang tergantung pada semua implementasi.


Benar Di semua sumber, panah diarahkan ke arah panggilan, dari kode panggilan ke implementasi. Jadi jika Anda ingin membuat perubahan kecil dalam implementasi ini ...

Oke, oke, saya mengerti apa yang Anda maksud. Perubahan dalam salah satu implementasi akan memerlukan kompilasi ulang semua file dengan sakelar, dan ini akan mengarah pada kenyataan bahwa semua yang memanggil sakelar ini akan dikompilasi ulang, misalnya, dalam kasus kami, fungsi untuk area.


Ya Setidaknya demikian untuk bahasa yang menggunakan tanggal modifikasi file untuk memahami apa yang perlu dibangun kembali.

Dan ini umumnya semua sistem dengan pengetikan statis, bukan?


Ya, dan beberapa sistem lain tanpa itu

Ini harus banyak dibangun kembali.


Dan banyak yang harus diulang.

Oke, tetapi dalam hal kelas sebaliknya?


Ya, karena kode yang memanggil fungsi untuk area tergantung pada antarmuka, dan implementasinya juga tergantung pada antarmuka ini.

Saya melihat. Kode untuk kelas Square akan mengimpor atau menggunakan atau menyertakan file dengan antarmuka Bentuk.


Benar Panah dalam file implementasi menunjuk ke arah yang berlawanan dengan panggilan. Ini diarahkan dari kode implementasi ke kode panggilan. Setidaknya ini akan menjadi kasus untuk bahasa yang diketik secara statis. Untuk bahasa yang diketik secara dinamis, kode yang memanggil fungsi untuk area tersebut tidak bergantung pada apa pun, karena menghubungkan terjadi di runtime.

Ya baiklah Yaitu, jika Anda membuat perubahan pada salah satu implementasi ...


Anda hanya perlu membangun kembali dan menginstal ulang kode dengan perubahan ini.

Ini karena dependensi diarahkan berlawanan dengan arah panggilan.


Ya, kami menyebutnya inversi ketergantungan.

Oke, mari kita simpulkan semuanya. Kelas dan struktur data saling bertentangan dalam tiga hal.


  • Fungsinya ada di kelas secara eksplisit, dan Anda hanya bisa menebak tentang keberadaan data. Struktur data secara eksplisit hadir dalam struktur data, dan Anda hanya bisa menebak fungsi apa yang tersedia.
  • Dalam kasus kelas, menambahkan tipe itu sederhana, tetapi menambahkan fungsi itu sulit. Dalam hal struktur, menambahkan fungsi itu mudah, tetapi menambahkan tipe itu sulit.
  • Struktur data mengarah pada kompilasi dan redistribusi kode panggilan. Kelas mengisolasi kode panggilan dan tidak perlu mengkompilasi ulang dan menggunakan lagi.

Ya itu benar. Dan ini harus diingat oleh setiap desainer dan arsitek perangkat lunak.

Source: https://habr.com/ru/post/id477712/


All Articles