Pada dasarnya saya perlu melakukan tindakan yang berbeda dengan syarat tertentu. Kode yang ada ditulis dengan cara ini
Antarmuka dasar
// DoSomething.java
interface DoSomething {
void letDoIt(String info);
}
Implementasi kelas pekerja pertama
class DoItThisWay implements DoSomething {
...
}
Implementasi kelas pekerja kedua
class DoItThatWay implements DoSomething {
...
}
Kelas utama
class Main {
public doingIt(String info) {
DoSomething worker;
if (info == 'this') {
worker = new DoItThisWay();
} else {
worker = new DoItThatWay();
}
worker.letDoIt(info)
}
Kode ini berfungsi dengan baik dan mudah dimengerti.
Sekarang, karena persyaratan baru, saya perlu memberikan informasi baru yang masuk akal DoItThisWay
.
Pertanyaan saya adalah: apakah gaya pengkodean berikut baik untuk menangani persyaratan ini.
Gunakan variabel dan metode kelas baru
// Use new class variable and method
class DoItThisWay implements DoSomething {
private int quality;
DoSomething() {
quality = 0;
}
public void setQuality(int quality) {
this.quality = quality;
};
public void letDoIt(String info) {
if (quality > 50) { // make use of the new information
...
} else {
...
}
} ;
}
Jika saya melakukannya dengan cara ini, saya perlu membuat perubahan yang sesuai dengan penelepon:
class Main {
public doingIt(String info) {
DoSomething worker;
if (info == 'this') {
int quality = obtainQualityInfo();
DoItThisWay tmp = new DoItThisWay();
tmp.setQuality(quality)
worker = tmp;
} else {
worker = new DoItThatWay();
}
worker.letDoIt(info)
}
Apakah ini gaya pengkodean yang baik? Atau bisakah saya melemparkannya saja
class Main {
public doingIt(String info) {
DoSomething worker;
if (info == 'this') {
int quality = obtainQualityInfo();
worker = new DoItThisWay();
((DoItThisWay) worker).setQuality(quality)
} else {
worker = new DoItThatWay();
}
worker.letDoIt(info)
}
java
coding-style
Anthony Kong
sumber
sumber
quality
ke konstruktorDoItThisWay
?DoItThisWay
danDoItThatWay
dilakukan sekali dalam konstruktorMain
.Main
adalah kelas hidup yang panjang dandoingIt
disebut berkali-kali.setQuality
metode ini akan dipanggil beberapa kali selama masa pakaiDoItThisWay
objek?Jawaban:
Saya berasumsi bahwa
quality
perlu diatur di samping setiapletDoIt()
panggilan pada aDoItThisWay()
.Masalah yang saya lihat timbul di sini adalah ini: Anda memperkenalkan penggabungan sementara (yaitu apa yang terjadi jika Anda lupa menelepon
setQuality()
sebelum memanggilletDoIt()
aDoItThisWay
?). Dan implementasi untukDoItThisWay
danDoItThatWay
berbeda (yang satu perlusetQuality()
menelepon, yang lain tidak).Meskipun ini mungkin tidak menyebabkan masalah sekarang, itu mungkin kembali menghantui Anda pada akhirnya. Mungkin bermanfaat untuk melihat kembali
letDoIt()
dan mempertimbangkan apakah informasi berkualitas mungkin perlu menjadi bagian dariinfo
Anda melewatinya; tapi ini tergantung dari detailnya.sumber
Dari sudut pandang saya tidak ada versi Anda. Pertama yang harus dihubungi
setQuality
sebelumletDoIt
dapat dipanggil adalah temporal coupling . Anda buntu melihatDoItThisWay
sebagai turunan dariDoSomething
, tetapi tidak (setidaknya tidak secara fungsional), itu agak sepertiIni akan membuat
Main
sesuatu sepertiDi lain pihak, Anda dapat meneruskan parameter ke kelas secara langsung (dengan asumsi ini mungkin) dan mendelegasikan keputusan yang akan digunakan untuk pabrik (ini akan membuat instance dipertukarkan lagi dan keduanya dapat diturunkan dari
DoSomething
). Ini akan membuatMain
terlihat seperti iniSaya sadar Anda yang menulisnya
Tapi Anda bisa menyimpan bagian yang mahal untuk dibuat di pabrik dan mengirimkannya ke konstruktor juga.
sumber
DoItThisWay
membutuhkan kualitas yang harus ditetapkan sebelum memanggilnyaletDoIt
berperilaku berbeda. Saya berharapDoSomething
untuk bekerja dengan cara yang sama (tidak menetapkan kualitas sebelumnya) untuk semua turunannya. Apakah ini masuk akal? Tentu saja ini agak buram, karena jika kita memanggilsetQuality
dari metode pabrik, klien akan agnostik mengenai apakah kualitasnya harus ditetapkan atau tidak.letDoIt()
adalah (tidak memiliki info tambahan) "Saya dapat menjalankan dengan benar (melakukan apa pun yang saya lakukan) jika Anda memberi sayaString info
". Membutuhkan yangsetQuality()
dipanggil sebelumnya memperkuat prasyarat panggilanletDoIt()
, dan dengan demikian akan menjadi pelanggaran terhadap LSP.letDoIt
" tidak akan mengeluarkan pengecualian, dan lupa memanggil "setQuality" akan membuatletDoIt
kemudian melemparkan pengecualian, maka saya akan setuju, implementasi seperti itu akan melanggar LSP. Tetapi semua itu tampak seperti asumsi yang sangat palsu bagi saya.Mari kita asumsikan
quality
tidak dapat diteruskan ke konstruktor, dan panggilan kesetQuality
diperlukan.Saat ini, potongan kode suka
terlalu kecil untuk menanamkan terlalu banyak pikiran ke dalamnya. IMHO itu terlihat agak jelek, tetapi tidak terlalu sulit untuk dipahami.
Masalah muncul ketika potongan kode seperti itu tumbuh dan karena refactoring Anda berakhir dengan sesuatu seperti
Sekarang, Anda tidak segera melihat apakah kode itu masih benar, dan kompiler tidak akan memberi tahu Anda. Jadi, memperkenalkan variabel sementara dari jenis yang benar, dan menghindari gips, sedikit lebih aman, tanpa upaya ekstra yang nyata.
Namun, saya sebenarnya akan memberikan
tmp
nama yang lebih baik:Penamaan tersebut membantu membuat kode yang salah terlihat salah.
sumber
DoItThisWay
mendapat parameter lebih spesifik - dengan apa yang Anda sarankan, nama harus diubah setiap waktu. Lebih baik menggunakan nama untuk variabel yang membuat tipe objek menjadi jelas, bukan metode mana yang tersedia.workerThisWay
menjadi sesuatu sepertiusingQuality
. Dalam cuplikan kode kecil itu, lebih aman untuk lebih spesifik. (Dan, jika ada frasa yang lebih baik dalam domain mereka daripada "usingQuality", gunakan.Antarmuka umum di mana inisialisasi bervariasi berdasarkan data runtime biasanya cocok dengan pola pabrik.
Kemudian DoThingsFactory dapat khawatir tentang mendapatkan dan mengatur informasi kualitas di dalam
getDoer(info)
metode sebelum mengembalikan objek DoThingsWithQuality yang asli dilemparkan ke antarmuka DoSomething.sumber