Menambahkan bidang ke kelas saat runtime - pola desain

15

Bayangkan pelanggan Anda ingin memiliki kemungkinan untuk menambahkan properti baru (misalnya warna) ke produk di eshop mereka di CMS mereka.

Alih-alih memiliki properti sebagai bidang:

class Car extends Product {
   protected String type;
   protected int seats;
}

Anda mungkin akan akhirnya melakukan sesuatu seperti:

class Product {
   protected String productName;
   protected Map<String, Property> properties;
}

class Property {
   protected String name;
   protected String value;
}

Artinya, membuat sistem tipe sendiri di atas yang sudah ada. Rasanya bagi saya seperti ini dapat dilihat sebagai membuat domain spesifik, atau tidak?

Apakah pendekatan ini merupakan pola desain yang dikenal? Apakah Anda akan memecahkan masalah secara berbeda? Saya tahu ada bahasa di mana saya bisa menambahkan bidang dalam runtime, tetapi bagaimana dengan basis data? Apakah Anda lebih suka menambahkan / mengubah kolom atau menggunakan sesuatu seperti yang ditunjukkan di atas?

Terima kasih atas waktu Anda :).

Filip
sumber
Tidak yakin bahasa apa yang Anda gunakan, tetapi jika itu C # Anda bisa menggunakan tipe dinamis yang pada dasarnya menyimpan KVP dalam kamus agak seperti apa yang Anda lakukan pada produk dan memungkinkan Anda untuk hanya menempel pada properti tanpa harus langsung menambahkannya ke koleksi sebagai koleksi. Anda tidak akan memiliki ketikan yang kuat. Saya tahu Anda meminta pola desain tetapi saya tidak merasa Anda perlu sesuatu yang rumit untuk menggunakannya. msdn.microsoft.com/en-us/magazine/gg598922.aspx
Tony
Tony: Saya menggunakan Java di sini, tetapi anggap itu pseudo coude :). Apakah C # memungkinkan saya untuk mempertahankan objek dinamis ke dalam basis data? Saya ragu, karena databse perlu mengetahui struktur data di muka.
Filipi
Ada Pola Desing Negara a-la Gang-of-Four, yang membuat objek tampak mengubah jenis atau kelasnya saat run-time. Alternatif lain adalah Pola Desain Pengamat atau Pola Desain Proksi
Nikos M.
1
Mengapa tidak menggunakan tipe data peta saja? Dalam DB itu dapat direpresentasikan sebagai {id} + {id, key, value}, jika Anda tidak meminta kinerja.
Shadows In Rain

Jawaban:

4

Selamat! Anda baru saja mengelilingi dunia bahasa pemrograman / sistem ketik, tiba di sisi lain dunia dari mana Anda pergi. Anda baru saja mendarat di perbatasan bahasa dinamis / objek berbasis prototipe!

Banyak bahasa dinamis (mis. JavaScript, PHP, Python) memungkinkan seseorang untuk memperluas atau mengubah properti objek saat runtime.

Bentuk ekstrim dari ini adalah bahasa berbasis prototipe seperti Self atau JavaScript. Mereka tidak memiliki kelas, secara tegas. Anda dapat melakukan hal-hal yang terlihat seperti pemrograman berbasis kelas, berorientasi objek dengan pewarisan, tetapi aturannya sangat santai dibandingkan dengan bahasa berbasis kelas yang lebih tajam seperti Java dan C #.

Langauges seperti PHP dan Python hidup di jalan tengah. Mereka memiliki sistem reguler berbasis kelas idiomatik. Tetapi atribut objek dapat ditambahkan, diubah, atau dihapus saat runtime - walaupun dengan beberapa batasan (seperti "kecuali untuk tipe bawaan") yang tidak Anda temukan di JavaScript.

Pertukaran besar bagi dinamisme ini adalah kinerja. Lupakan seberapa kuat atau lemahnya bahasa itu diketik, atau seberapa baik dapat dikompilasi ke kode mesin. Objek dinamis harus direpresentasikan sebagai peta / kamus fleksibel, bukan struct sederhana. Ini menambahkan overhead ke setiap akses objek. Beberapa program berusaha keras untuk mengurangi overhead ini (misalnya dengan penugasan phantom kwarg dan kelas berbasis slot di Python), tetapi overhead tambahan biasanya hanya setara untuk kursus dan harga tiket masuk.

Kembali ke desain Anda, Anda mencangkok kemampuan untuk memiliki properti dinamis ke subset dari kelas Anda. A Productdapat memiliki atribut variabel; mungkin suatu Invoiceatau Orderakan dan tidak bisa. Itu bukan cara yang buruk untuk pergi. Ini memberi Anda fleksibilitas untuk memiliki variasi di mana Anda membutuhkannya, sambil tetap dalam bahasa yang ketat dan sistem jenis. Di sisi bawah, Anda bertanggung jawab untuk mengelola properti fleksibel tersebut, dan Anda mungkin harus melakukannya melalui mekanisme yang terlihat sedikit berbeda dari atribut yang lebih asli. p.prop('tensile_strength')bukannya p.tensile_strength, misalnya, dan p.set_prop('tensile_strength', 104.4)bukannyap.tensile_strength = 104.4. Tetapi saya telah bekerja dengan dan membangun banyak program dalam Pascal, Ada, C, Java dan bahkan bahasa dinamis yang menggunakan akses pengambil-penyetel untuk tipe atribut non-standar; pendekatannya jelas bisa diterapkan.

Oleh karena itu, ketegangan antara tipe statis dan dunia yang sangat bervariasi ini sangat umum. Masalah analog sering terlihat ketika merancang skema database, terutama untuk penyimpanan data relasional dan pra-relasional. Kadang-kadang ditangani dengan membuat "baris super" yang berisi cukup banyak fleksibilitas untuk menampung atau menentukan gabungan dari semua variasi yang dibayangkan, kemudian memasukkan semua data yang masuk ke dalam bidang tersebut. The WordPress wp_postsmeja , misalnya, memiliki bidang-bidang seperti comment_count, ping_status, post_parentdan post_date_gmtyang hanya menarik dalam kondisi tertentu, dan bahwa dalam prakteknya sering kosong. Pendekatan lain adalah, seperti tabel normalisasiwp_options , sangat mirip dengan AndaPropertykelas. Meskipun memerlukan manajemen yang lebih eksplisit, item di dalamnya jarang kosong. Database berorientasi objek dan dokumen (misalnya MongoDB) seringkali lebih mudah berurusan dengan perubahan opsi, karena mereka dapat membuat dan mengatur atribut dengan cukup banyak.

Jonathan Eunice
sumber
0

Saya suka pertanyaan, dua sen saya:

Dua pendekatan Anda sangat berbeda:

  • Yang pertama adalah OO dan sangat diketik - tetapi tidak dapat diperpanjang
  • Yang kedua diketik dengan lemah (string merangkum apa saja)

Dalam C ++, banyak yang akan menggunakan std :: map of boost :: varian untuk mencapai campuran keduanya.

Penyimpangan: Perhatikan bahwa beberapa bahasa, seperti C #, memungkinkan pembuatan jenis yang dinamis. Yang bisa menjadi solusi bagus untuk masalah umum penambahan anggota secara dinamis. Namun, "memodifikasi / menambahkan" jenis setelah kompilasi tidak merusak sistem jenis itu sendiri, dan membuat jenis "dimodifikasi" Anda hampir tidak berguna (misalnya, bagaimana Anda mengakses properti yang ditambahkan seperti itu, karena Anda bahkan tidak tahu mereka ada? Satu-satunya cara yang masuk akal akan menjadi refleksi sistematis atas setiap objek ... diakhiri dengan bahasa dinamis murni _ Anda dapat merujuk ke 'dinamis' .NET kata kunci)

quantdev
sumber
Membuat jenis pada jahitan runtime menarik tetapi terlalu eksotis bagi saya (saya pemrograman di Jawa). Solusi seperti itu tidak akan berfungsi, jika saya ingin menyimpan objek di databse, yang selalu diketik kuat saya percaya. Solusi yang diketik dengan lemah yang saya usulkan dapat disimpan dalam database dengan mudah.
Filipi
0

Membuat jenis saat runtime terdengar jauh lebih rumit daripada hanya membuat lapisan abstraksi. Sangat umum membuat abstraksi untuk memisahkan sistem.

Izinkan saya menunjukkan contoh dari latihan saya. Pertukaran Moskow memiliki inti perdagangan yang disebut Plaza2 dengan API pedagang. Pedagang menulis program mereka untuk bekerja dengan data keuangan. Masalahnya adalah bahwa data ini sangat besar, kompleks, dan sangat rentan terhadap perubahan. Itu dapat berubah setelah produk keuangan baru diperkenalkan atau perubahan kliring berubah. Sifat perubahan di masa depan tidak bisa diprediksi. Secara harfiah, ini dapat berubah setiap hari dan programmer yang buruk harus mengedit kode dan merilis versi baru, dan pedagang yang marah harus merevisi sistem mereka.

Keputusan yang jelas adalah menyembunyikan semua neraka finansial di balik abstraksi. Mereka telah menggunakan abstraksi tabel SQL yang terkenal. Bagian terbesar dari inti mereka dapat bekerja dengan skema yang valid, sama seperti perangkat lunak trader yang secara dinamis dapat menguraikan skema dan mencari tahu apakah itu kompatibel dengan sistem mereka.

Kembali ke contoh Anda, adalah normal untuk membuat bahasa abstrak di depan beberapa logika. Itu bisa "properti", "tabel", "pesan", atau bahkan bahasa manusia, tetapi perhatikan kelemahan dari pendekatan ini:

  • Lebih banyak kode untuk penguraian dan validasi (dan lebih banyak waktu luang). Semua yang dilakukan kompiler untuk Anda dengan pengetikan statis harus Anda lakukan pada saat run-time.
  • Dokumentasi lebih lanjut tentang pesan, tabel atau primitif lainnya. Semua kompleksitas beralih dari kode ke semacam skema atau standar. Berikut adalah contoh skema neraka finansial yang disebutkan di atas: http://ftp.moex.com/pub/FORTS/Plaza2/p2gate_en.pdf (lusinan halaman tabel)
astef
sumber
0

Apakah pendekatan ini merupakan pola desain yang dikenal?

Dalam XML dan HTML, ini akan menjadi atribut untuk simpul / elemen. Saya juga mendengar mereka disebut properti diperluas, pasangan nama / nilai, dan parameter.

Apakah Anda akan memecahkan masalah secara berbeda?

Begitulah cara saya memecahkan masalah, ya.

Saya tahu ada bahasa di mana saya bisa menambahkan bidang dalam runtime, tetapi bagaimana dengan basis data?

Database akan seperti Java, dalam beberapa hal. Dalam pesudo-sql:

TABLE products
(
    product_name VARCHAR(50),
    product_id INTEGER AUTOINCREMENT
)

TABLE attributes
(
    product_id INTEGER,
    name VARCHAR(50),
    value VARCHAR(2000)
)

Ini akan sesuai dengan Java

class Product {
   protected String productName;
   protected Map<String, String> properties;
}

Perhatikan bahwa tidak perlu untuk kelas Properti, karena Peta menyimpan nama sebagai kunci.

Apakah Anda lebih suka menambahkan / mengubah kolom atau menggunakan sesuatu seperti yang ditunjukkan di atas?

Saya sudah mencoba menambahkan / mengubah hal kolom, dan itu adalah mimpi buruk. Itu bisa dilakukan, tetapi hal-hal tetap tidak sinkron dan saya tidak pernah berhasil dengan baik. Struktur tabel yang saya uraikan di atas jauh lebih sukses. Jika Anda perlu untuk melakukan pencarian dan ketertiban oleh ini, pertimbangkan untuk menggunakan atribut tabel untuk setiap jenis data ( date_attributes, currency_attributes, dll) atau menambahkan beberapa sifat sebagai kolom database lama baik dalam tabel produk. Laporan seringkali jauh lebih mudah untuk ditulis pada kolom basis data daripada sub tabel.

Guy Schalnat
sumber