Mana yang lebih baik: sekelompok getter atau 1 metode dengan parameter string pemilihan?

15

Domain pengetahuan kami melibatkan orang-orang yang berjalan di atas piring penekan tekanan dengan kaki telanjang. Kami melakukan pengenalan gambar yang menghasilkan objek dari kelas 'Kaki', jika kaki manusia dikenali dalam data sensor.

Ada beberapa perhitungan yang harus dilakukan pada data kaki.

Sekarang, API mana yang lebih baik:

class Foot : public RecognizedObject  { 
  MaxPressureFrame getMaxPressureFrame();
  FootAxis getFootAxis();
  AnatomicalZones getAnatomicalZones();

  // + similar getters for other calculations

  // ...
}

Atau:

class Foot : public RecognizedObject {
  virtual CalculationBase getCalculation(QString aName);

  // ...
}

Sekarang, ada banyak pro dan kontra yang bisa saya buat, tapi saya tidak bisa memutuskan mana yang paling penting. Catatan, ini adalah aplikasi pengguna akhir, bukan perpustakaan perangkat lunak yang kami jual.

Ada saran?

Beberapa pro untuk pendekatan pertama dapat:

  • CIUMAN - semuanya sangat konkret. API, tetapi implementasinya juga.
  • nilai pengembalian sangat diketik.
  • mewarisi dari kelas ini adalah bukti bodoh. Tidak ada yang bisa ditimpa, hanya ditambahkan.
  • API sangat tertutup, tidak ada yang masuk, tidak ada yang bisa ditimpa, jadi lebih sedikit yang bisa salah.

Beberapa con:

  • Jumlah getter akan bertambah, karena setiap perhitungan baru yang kami temukan akan ditambahkan ke daftar
  • API lebih cenderung berubah, dan jika memecah perubahan diperkenalkan, kita membutuhkan versi API baru, Foot2.
  • dalam hal penggunaan kembali kelas di proyek lain, kita mungkin tidak perlu setiap perhitungan

Beberapa pro untuk pendekatan kedua:

  • lebih fleksibel
  • api lebih kecil kemungkinannya untuk berubah, (dengan asumsi kita mendapatkan abstraksi yang benar, jika tidak, perubahan akan lebih mahal)

Beberapa con:

  • diketik dengan longgar. Membutuhkan gips pada setiap panggilan.
  • parameter string - Saya punya firasat buruk tentang itu (bercabang pada nilai string ...)
  • Tidak ada use case / persyaratan saat ini yang mengamanatkan fleksibilitas ekstra, tetapi mungkin ada di masa depan.
  • API memberlakukan batasan: setiap perhitungan harus berasal dari kelas dasar. Mendapatkan perhitungan akan dipaksa melalui metode 1 ini, dan melewati parameter tambahan tidak akan mungkin, kecuali jika kita merancang cara yang lebih dinamis, super-fleksibel untuk melewatkan parameter yang meningkatkan kompleksitas bahkan lebih.
Bgie
sumber
5
Anda bisa membuat enumdan mengaktifkan nilainya. Tetap saja, saya pikir pilihan kedua adalah jahat, karena menyimpang dari KISS.
Vorac
Sulit untuk menemukan semua penggunaan perhitungan tertentu jika Anda menggunakan parameter string untuk memicunya. Sulit menjadi 100% Anda menemukan semuanya.
Konrad Morawski
Ambil yang terbaik dari dua dunia dan tulis sebuah façade dengan sekelompok getter yang memohon getCalculation().
nalply
1
Enum jelas lebih baik daripada string! Saya tidak memikirkan hal ini. Mereka membatasi API dan mencegah penyalahgunaan parameter string (seperti concat token dan omong kosong lainnya). Jadi saya kira perbandingannya adalah antara opsi 1 dan opsi 2 dengan enum bukan string.
Bgie

Jawaban:

6

Saya pikir dalam pendekatan pertama akan membuahkan hasil. String ajaib dapat membuat masalah berikut: Kesalahan pengetikan, penyalahgunaan, keamanan jenis pengembalian non-sepele, kurangnya penyelesaian kode, kode tidak jelas (apakah versi ini memiliki fitur itu? Saya kira kita akan mengetahuinya saat runtime). Menggunakan enum akan menyelesaikan beberapa masalah tersebut, tetapi mari kita lihat kontra yang Anda ajukan:

  • Jumlah getter akan bertambah, karena setiap perhitungan baru yang kami temukan akan ditambahkan ke daftar

Benar, itu bisa menjengkelkan, tetapi hal itu menjaga hal-hal yang bagus dan ketat, dan memberi Anda penyelesaian kode di mana pun dalam proyek Anda dalam IDE modern apa pun, dengan komentar judul yang baik yang jauh lebih berguna daripada enum.

  • API lebih cenderung berubah, dan jika memecah perubahan diperkenalkan, kita membutuhkan versi API baru, Foot2.

Benar, tapi itu sebenarnya pro besar;) Anda bisa mendefinisikan antarmuka untuk sebagian API, dan kemudian Anda tidak perlu mengkompilasi ulang kelas dependen yang tidak terpengaruh oleh API yang lebih baru (Jadi tidak perlu untuk Foot2). Itu memungkinkan decoupling yang lebih baik, ketergantungannya sekarang dari antarmuka dan bukan implementasinya. Apalagi jika antarmuka yang ada berubah, Anda akan memiliki kesalahan kompilasi di kelas dependen, yang bagus untuk mencegah kode basi.

  • dalam hal penggunaan kembali kelas di proyek lain, kita mungkin tidak perlu setiap perhitungan

Saya tidak melihat bagaimana menggunakan senar ajaib atau enum akan membantu dengan itu ... Jika saya mengerti dengan benar, Anda memasukkan kode di kelas Foot atau Anda memecahnya ke beberapa kelas yang lebih kecil, dan itu berlaku untuk kedua opsi

pengguna116462
sumber
Saya suka gagasan API parsial dengan antarmuka, tampaknya kedepan. Saya akan pergi dengan yang itu. Terima kasih. Jika harus menjadi terlalu berantakan (kaki menerapkan terlalu banyak antarmuka), menggunakan beberapa kelas adaptor kecil akan lebih fleksibel: Jika ada beberapa variasi kaki dengan api yang berbeda (seperti kaki, kaki manusia, kaki anjing, kaki manusia, versi 2) mungkin ada adaptor kecil untuk masing-masing untuk memungkinkan satu widget GUI untuk bekerja dengan semuanya ...
Bgie
Keuntungan menggunakan pemilih perintah adalah seseorang dapat memiliki implementasi yang menerima perintah yang tidak dimengerti memanggil metode pembantu statis yang disediakan dengan antarmuka. Jika perintah tersebut mewakili sesuatu yang dapat dilakukan dengan hampir semua implementasi menggunakan pendekatan tujuan umum, tetapi beberapa implementasi mungkin dapat dilakukan melalui cara yang lebih baik [pertimbangkan misalnya IEnumerable<T>.Count], pendekatan semacam itu memungkinkan kode untuk menikmati manfaat kinerja dari yang baru. fitur antarmuka saat menggunakan implementasi yang mendukungnya, tetapi tetap kompatibel dengan implementasi lama.
supercat
12

Saya akan merekomendasikan opsi 3: Jelaskan bahwa perhitungan bukan bagian intrinsik dari abstraksi a Foot, tetapi operasikanlah. Kemudian Anda dapat membagi Footdan perhitungannya menjadi kelas yang terpisah, seperti ini:

class Foot : public RecognizedObject {
public:
    // Rather low-level API to access all characteristics that might be needed by a calculation
};

class MaxPressureFrame {
public:
    MaxPressureFrame(const Foot& aFoot); // Performs the calculation based on the information in aFoot
    //API for accessing the results of the calculation
};

// Similar classes for other calculations

Dengan cara ini, Anda masih memiliki pengetikan yang kuat dari perhitungan Anda, dan Anda dapat menambahkan yang baru tanpa memengaruhi kode yang ada (kecuali Anda membuat kesalahan serius dalam jumlah informasi yang diekspos oleh Foot).

Bart van Ingen Schenau
sumber
Jelas lebih bagus daripada opsi 1 dan 2. Ini hanya beberapa langkah dari penggunaan pola desain strategi.
Brian
4
Ini mungkin tepat. Ini mungkin berlebihan. Tergantung pada seberapa rumit perhitungannya. Anda akan menambahkan MaxPressureFrameStrategy dan MaxPressureFrameStrategyFactory? Dan itu cenderung mengubah kaki menjadi objek anemia.
user949300
Meskipun ini adalah alternatif yang bagus, membalikkan dependensi tidak akan berfungsi dalam kasus kami. Kaki juga harus bertindak sebagai semacam mediator, karena beberapa perhitungan perlu dihitung ulang jika yang lain berubah (karena pengguna mengubah parameter atau lebih).
Bgie
@Bgie: Dengan ketergantungan antar perhitungan, saya setuju dengan @ user116462 bahwa opsi pertama adalah yang terbaik.`
Bart van Ingen Schenau