Saya memiliki metode yang membuat file data setelah berbicara dengan papan digital:
CreateDataFile(IFileAccess boardFileAccess, IMeasurer boardMeasurer)
Di sini boardFileAccess
dan boardMeasurer
merupakan contoh yang sama dari Board
objek yang mengimplementasikan keduanya IFileAccess
dan IMeasurer
. IMeasurer
digunakan dalam kasus ini untuk metode tunggal yang akan menetapkan satu pin di papan aktif untuk membuat pengukuran sederhana. Data dari pengukuran ini kemudian disimpan secara lokal di papan menggunakan IFileAccess
. Board
terletak di proyek terpisah.
Saya sampai pada kesimpulan bahwa CreateDataFile
melakukan satu hal dengan melakukan pengukuran cepat dan kemudian menyimpan data, dan melakukan keduanya dengan metode yang sama lebih intuitif untuk orang lain yang menggunakan kode ini kemudian harus melakukan pengukuran dan menulis ke file sebagai pemanggilan metode terpisah.
Bagi saya, rasanya aneh untuk melewatkan objek yang sama ke metode dua kali. Aku sudah dianggap membuat antarmuka lokal IDataFileCreator
yang akan memperpanjang IFileAccess
dan IMeasurer
kemudian memiliki implementasi yang berisi Board
contoh yang hanya akan memanggil diperlukan Board
metode. Menimbang bahwa objek papan yang sama akan selalu digunakan untuk pengukuran dan penulisan file, apakah merupakan praktik yang buruk untuk melewatkan objek yang sama ke metode dua kali? Jika demikian, apakah menggunakan antarmuka lokal dan implementasi merupakan solusi yang tepat?
sumber
Jawaban:
Tidak, ini baik-baik saja. Ini hanya berarti bahwa API direkayasa berlebihan terkait dengan aplikasi Anda saat ini .
Tetapi itu tidak membuktikan bahwa tidak akan pernah ada kasus penggunaan di mana sumber data dan pengukur berbeda. Inti dari API adalah untuk menawarkan kemungkinan programmer aplikasi, tidak semuanya akan digunakan. Anda tidak boleh secara artifisial membatasi apa yang dapat dilakukan oleh pengguna API kecuali jika mempersulit API sehingga pemahaman internet menurun.
sumber
Setuju dengan jawaban @ KilianFoth bahwa ini baik-baik saja.
Namun, jika Anda mau, Anda bisa membuat metode yang mengambil objek tunggal yang mengimplementasikan kedua antarmuka:
Tidak ada alasan umum bahwa argumen harus objek yang berbeda, dan jika suatu metode memang membutuhkan argumen yang berbeda, itu akan menjadi persyaratan khusus kontraknya harus menjelaskan.
sumber
Saya pikir ini masalah Anda sebenarnya. Metodenya tidak melakukan satu hal. Ini melakukan dua, operasi berbeda yang melibatkan I / O ke perangkat yang berbeda , yang keduanya memuat ke objek lain:
Ini adalah dua operasi I / O yang berbeda. Khususnya, yang pertama tidak mengubah sistem file dengan cara apa pun.
Bahkan, kita harus perhatikan bahwa ada langkah tengah tersirat:
API Anda harus menyediakan masing-masing secara terpisah dalam beberapa bentuk. Bagaimana Anda tahu seorang penelepon tidak ingin melakukan pengukuran tanpa menyimpannya di mana pun? Bagaimana Anda tahu mereka tidak ingin mendapatkan pengukuran dari sumber lain? Bagaimana Anda tahu mereka tidak ingin menyimpannya di tempat lain selain perangkat? Ada alasan bagus untuk memisahkan operasi. Pada telanjang minimum, masing-masing bagian individu harus tersedia untuk pemanggil apapun. Saya seharusnya tidak dipaksa untuk menulis pengukuran ke file jika use case saya tidak meminta untuk itu.
Sebagai contoh, Anda dapat memisahkan operasi seperti ini.
IMeasurer
memiliki cara untuk mengambil pengukuran:Jenis pengukuran Anda mungkin hanya sesuatu yang sederhana, seperti
string
ataudecimal
. Saya tidak mendesak Anda membutuhkan antarmuka atau kelas untuk itu, tetapi itu membuat contoh di sini lebih umum.IFileAccess
memiliki beberapa metode untuk menyimpan file:Maka Anda perlu cara membuat serial pengukuran. Bangun itu ke dalam kelas atau antarmuka yang mewakili pengukuran, atau miliki metode utilitas:
Tidak jelas apakah Anda memiliki operasi serialisasi ini belum.
Pemisahan semacam ini meningkatkan API Anda. Ini memungkinkan penelepon memutuskan apa yang mereka butuhkan dan kapan, daripada memaksakan ide-ide Anda sebelumnya tentang apa yang saya / O lakukan. Penelepon harus memiliki kontrol untuk melakukan operasi yang valid , baik menurut Anda berguna atau tidak.
Setelah Anda memiliki implementasi yang terpisah untuk setiap operasi,
CreateDataFile
metode Anda menjadi singkatanKhususnya, metode Anda menambahkan nilai yang sangat kecil setelah Anda melakukan semua ini. Baris kode di atas tidak sulit bagi penelepon Anda untuk digunakan secara langsung, dan metode Anda murni untuk kenyamanan maksimal. Itu harus dan merupakan sesuatu yang opsional . Dan itu adalah cara yang benar untuk berperilaku API.
Setelah semua bagian yang relevan difaktorkan dan kami telah mengakui bahwa metode ini hanya kenyamanan, kami perlu mengulangi pertanyaan Anda:
Kasus penggunaan apa yang paling umum untuk penelepon Anda?
Jika seluruh poinnya adalah untuk membuat case use khas dari mengukur dan menulis ke papan yang sama sedikit lebih nyaman, maka masuk akal untuk membuatnya tersedia di
Board
kelas secara langsung:Jika ini tidak meningkatkan kenyamanan, maka saya tidak akan repot dengan metode ini sama sekali.
Ini menjadi metode kenyamanan memunculkan satu pertanyaan lain.
Haruskah
IFileAccess
antarmuka tahu tentang jenis pengukuran dan bagaimana cara membuat serial? Jika demikian, Anda dapat menambahkan metode keIFileAccess
:Sekarang penelepon lakukan saja ini:
yang sama pendek dan mungkin lebih jelas daripada metode kenyamanan Anda sebagaimana dipahami dalam pertanyaan.
sumber
Klien yang mengkonsumsi tidak harus berurusan dengan sepasang barang saat satu barang mencukupi. Dalam kasus Anda, mereka hampir tidak, sampai doa
CreateDataFile
.Solusi potensial yang Anda sarankan adalah membuat antarmuka turunan gabungan. Namun, pendekatan ini membutuhkan objek tunggal yang mengimplementasikan kedua antarmuka, yang agak membatasi, bisa dibilang abstraksi bocor yang pada dasarnya disesuaikan untuk implementasi tertentu. Pertimbangkan betapa rumitnya jika seseorang ingin mengimplementasikan dua antarmuka dalam objek terpisah: mereka harus mem-proxy semua metode di salah satu antarmuka untuk meneruskan ke objek lain. (FWIW, opsi lain adalah hanya menggabungkan antarmuka daripada membutuhkan satu objek harus mengimplementasikan dua antarmuka melalui antarmuka turunan.)
Namun, pendekatan lain yang kurang membatasi / mendikte pelaksanaan
IFileAccess
adalah dipasangkan denganIMeasurer
komposisi in, sehingga salah satu dari mereka terikat dan referensi yang lain. (Ini agak meningkatkan abstraksi dari salah satu dari mereka karena sekarang mewakili pasangan juga.) KemudianCreateDataFile
bisa hanya mengambil satu dari referensi, katakanlahIFileAccess
, dan masih mendapatkan yang lain sesuai kebutuhan. Implementasi Anda saat ini sebagai objek yang mengimplementasikan kedua antarmuka hanyareturn this;
untuk referensi komposisi, di sini pengambil untukIMeasurer
diIFileAccess
.Jika pasangan ternyata salah di beberapa titik dalam pengembangan, yang mengatakan kadang-kadang pengukur yang berbeda digunakan dengan akses file yang sama, maka Anda dapat melakukan pemasangan yang sama tetapi pada tingkat yang lebih tinggi, yang berarti antarmuka tambahan yang diperkenalkan akan bukan menjadi antarmuka turunan, melainkan antarmuka yang memiliki dua getter, memasangkan akses file dan pengukur bersama melalui komposisi daripada derivasi. Klien yang mengkonsumsi kemudian memiliki satu hal yang perlu diperhatikan selama pasangan bertahan, dan masing-masing objek untuk ditangani (untuk menyusun pasangan baru) bila perlu.
Pada catatan lain, saya mungkin bertanya siapa yang memiliki
CreateDataFile
, dan pertanyaannya adalah siapa pihak ketiga ini. Kami sudah memiliki beberapa klien pemakai yang memanggilCreateDataFile
, objek / kelas pemilikCreateDataFile
, danIFileAccess
danIMeasurer
. Kadang-kadang ketika kita mengambil konteks konteks yang lebih luas, organisasi alternatif, terkadang lebih baik, dapat muncul. Sulit dilakukan di sini karena konteksnya tidak lengkap, jadi hanya makanan untuk dipikirkan.sumber
Beberapa telah mengemukakan bahwa
CreateDataFile
melakukan terlalu banyak. Saya mungkin menyarankan bahwa alih-alihBoard
melakukan terlalu banyak, karena mengakses file sepertinya menjadi perhatian terpisah dari anggota dewan lainnya.Namun, jika kami berasumsi bahwa ini bukan kesalahan, masalah yang lebih besar adalah bahwa antarmuka harus ditentukan oleh klien, dalam hal ini
CreateDataFile
.The Antarmuka Pemisahan Prinsip menyatakan bahwa klien tidak harus bergantung pada lebih dari sebuah antarmuka dari apa yang dibutuhkan. Meminjam frasa dari jawaban lain ini , ini dapat diparafrasekan sebagai "sebuah antarmuka didefinisikan oleh apa yang dibutuhkan klien."
Sekarang, dimungkinkan untuk membuat antarmuka khusus klien ini menggunakan
IFileAccess
danIMeasurer
sebagai jawaban lain menyarankan, tetapi pada akhirnya, klien ini harus memiliki antarmuka yang dibuat khusus untuk itu.sumber