Apakah buruk membuat kelas yang tujuan utamanya harus dikonversi ke kelas lain secara implisit?


10

Bayangkan situasi di mana kami menggunakan pustaka yang memungkinkan Anda membuat Circleobjek, di mana Anda dapat menentukan radius dan pusat lingkaran untuk mendefinisikannya. Namun, untuk beberapa alasan, dibutuhkan juga flavourparameter yang diperlukan . Sekarang katakanlah saya benar-benar perlu menggunakannya Circledi aplikasi saya sendiri, tetapi untuk keperluan aplikasi saya, saya dapat mengatur rasanya Flavours.Cardboardsetiap saat.

Untuk "memecahkan" ini, saya membuat Circlekelas saya sendiri di namespace yang berbeda, yang hanya mengambil radiusdan centersebagai parameter, tetapi memiliki konverter implisit ke kelas perpustakaan eksternal Circleyang baru saja membuat Circle(this.radius, this.center, Flavours.Cardboard)objek. Jadi di mana pun saya membutuhkan jenis lain Circle, saya membiarkan konversi otomatis terjadi.

Apa konsekuensi dari menciptakan kelas seperti itu? Apakah ada solusi yang lebih baik? Apakah ada bedanya jika aplikasi saya adalah API yang dibangun di atas perpustakaan eksternal ini, yang dimaksudkan untuk digunakan oleh programmer lain?


Ini tampak seperti variasi dari Pola Adaptor , meskipun nampaknya memiliki nilai yang meragukan di sini (itu hanya kenyamanan untuk menghindari pengaturan parameter).
Robert Harvey

5
Mengapa tidak membuat MakeCircle fungsi ?
user253751

1
@immibis Thay adalah pikiran pertamaku. Ketika saya membuat game, saya akan sering membuat fungsi di sepanjang garis makePlayeritu sendiri hanya menerima koordinasi untuk menempatkan pemain, tetapi mendelegasikan ke konstruktor yang jauh lebih kompleks.
Carcigenicate

Jawaban:


13

Meskipun tidak selalu buruk, sangat jarang bahwa konversi tersirat adalah pilihan terbaik Anda.

Ada beberapa masalah.

  1. Konversi tersirat tidak terlalu mudah dibaca.
  2. Karena Anda membuat objek baru, perubahan apa pun pada objek asli tidak akan terlihat oleh objek yang Anda konversi, yang mengarah ke bug.
  3. Jika Anda membuang benda itu, itu sampah tambahan untuk dibersihkan.
  4. Jika ada masalah, itu akan terjadi ketika konversi terjadi, bukan ketika hal itu dibuat, membuat bug yang lebih sulit untuk dilacak.

Secara umum, ada solusi yang lebih baik.

  1. Buat pembungkus tipis Anda sendiri yang menggunakan kelas / kerangka kerja lain secara internal.
  2. Buat metode penolong yang mengambil argumen konstruktor yang Anda inginkan dan memasok yang sudah diperbaiki, mengembalikan objek nyata tanpa harus menentukan argumen yang tidak Anda pedulikan.
  3. Mewarisi dari kelas masalah dan menyediakan Anda sendiri, konstruktor yang lebih baik.
  4. Sadarilah bahwa menyampaikan argumen tambahan sebenarnya bukan masalah besar.

Secara pribadi, saya menemukan # 2 menjadi yang paling sederhana untuk diimplementasikan, dan paling tidak memberatkan pada desain. Yang lain bisa baik-baik saja, mengingat situasinya dan apa lagi yang Anda coba lakukan dengan kelas-kelas ini.

Konversi implisit adalah pilihan terakhir, dan sepertinya benar-benar layak bagi saya ketika saya memiliki functor gaya C ++ yang saya coba buat - objek strategi yang secara implisit saya konversi ke tipe delegasi.


1

Mengingat skenario yang Anda gambarkan, Anda dapat memikirkan ini dalam hal aplikasi fungsi parsial.

Konstruktor adalah fungsi (setidaknya dalam teori; dalam C #, Anda dapat membuat "fungsi pabrik" yang memanggil konstruktor):

Func<double, Point, Flavour, Circle> MakeCircle = (r, p, f) => new Circle(r, p, f);

untuk aplikasi parsial, berikut ini sudah cukup:

public static Func<T1, T2, R> Partial<T1, T2, T3, R>(this Func<T1, T2, T3, R> func, T3 t3)
   => (t1, t2) => func(t1, t2, t3);

Anda sekarang bisa mendapatkan konstruktor yang hanya membutuhkan 2 parameter:

Func<double, Point, Circle> MakeCardboardCircle = Circle.Partial(Flavours.Cardboard)

Jadi sekarang Anda memiliki fungsi pabrik dengan parameter yang Anda inginkan

Circle c = MakeCardboardCircle(1.0, new Point(0, 0)))

BTW, ini jelas setara dengan opsi 2 di atas, hanya dari perspektif yang lebih fungsional.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.