Hindari getter dan setter, menampilkan informasi pengguna

10

Latar Belakang

Saya sedang membaca "buku Kode Bersih", dan, secara paralel, saya sedang mengerjakan objek senam Kata seperti rekening bankir, dan saya terjebak pada aturan itu:

Aturan 9 dari objek senam adalah kita tidak menggunakan pengambil atau setter.

Tampaknya cukup menyenangkan, dan saya setuju dengan prinsip ini. Terlebih lagi, pada halaman 98-99 dari Clean Code, penulis menjelaskan bahwa pengambil / pemecah gelombang memutuskan abstraksi, dan bahwa kita tidak harus menanyakan objek kita, tetapi kita harus memberi tahu objek kita.

Ini masuk akal dalam pikiran saya, dan saya sepenuhnya setuju dengan prinsip ini. Masalahnya muncul dalam praktik.

Konteks

Sebagai contoh, saya memiliki aplikasi di mana saya harus mendaftar beberapa pengguna, dan untuk menampilkan detail pengguna.

Pengguna saya terdiri dari:

-> Name
   --> Firstname --> String
   --> Lastname --> String
-> PostalAddress
   --> Street --> String
   --> PostalCode --> String

Masalah

Bagaimana saya bisa melakukan, atau apa yang bisa saya lakukan untuk menghindari getter ketika saya hanya perlu menampilkan informasi sederhana ( dan saya harus mengonfirmasi bahwa saya tidak perlu operasi tambahan pada bidang tertentu ) untuk menampilkan nilai Firstname dengan sederhana ( acak) dukungan keluaran?

Apa yang muncul di pikiran saya

Salah satu solusinya adalah membuat:

user.getName().getFirstName().getStringValue()

Yang benar-benar mengerikan, melanggar banyak aturan benda-benda senam, dan melanggar Hukum Demeter.

Yang lain akan menjadi sesuatu seperti:

String firstName = user.provideFirstnameForOutput();
// That would have called in the user object =>
String firstName = name.provideFirstnameForOutput();
// That would have called in the name object =>
String firstName = firstname.provideFirstnameForOutput();

Tapi saya tidak merasa nyaman dengan solusi ini, yang sepertinya hanya menjadi "pengakses pesanan tingkat tinggi" seperti memintas pembuat / penyetel standar dengan metode yang hanya bertujuan untuk menyesuaikan dengan hukum Demeter ...

Ada ide ?

mfrachet
sumber

Jawaban:

17

Kesalahpahaman umum tentang ide menghindari getter dan setter adalah untuk menghindarinya di mana-mana, yang tidak mungkin ketika Anda sampai pada permukaan arsitektur Anda berinteraksi dengan pengguna.

Anda harus menghindari penggunaan getter dan setter di bagian logika bisnis aplikasi Anda, di mana objek harus dilindungi menggunakan agregat yang menyediakan konteks, dan metode harus bertindak sebagai perintah.

Untuk menghindari getter dan setter Anda dapat merancang solusi yang mirip dengan pemrograman reaktif , menerapkan sistem pelaporan melalui entitas yang dapat diamati, tetapi ini sangat menyulitkan arsitektur dan tidak masuk akal dalam tingkat CRUD aplikasi Anda, meskipun desainnya sangat bagus untuk antarmuka pengguna.

Apakah Anda harus mempertimbangkan menggunakan getter / setter tergantung sepenuhnya pada bagian aplikasi yang sedang Anda kerjakan. Jika kekhawatiran Anda adalah antarmuka pengguna yang menggunakan getter benar-benar baik, untuk logika bisnis, di mana Anda akan menjalankan bagian dari kode berdasarkan nilai yang diambil melalui pengambil, tidak terlalu banyak (ini menjerit bahwa logika seharusnya benar-benar dienkapsulasi dalam kelas yang Anda panggil pengambil).

Selain itu, hukum demeter bukan tentang menghitung titik, tetapi hanya tentang merobek kelas yang menyediakan konteks dengan menggunakan getter di kelas untuk mendapatkan komponennya yang tidak boleh Anda akses sendiri.

Jika Anda merasa antarmuka pengguna terlalu dalam di dalam model bisnis Anda, Anda dapat berpikir tentang memperkenalkan model tampilan ke sistem Anda yang bertanggung jawab untuk mengubah bagian-bagian tertentu dari model ke representasi visual.

Andy
sumber
Oke, saya memikirkan saran itu seperti mapper antara entitas domain saya, ke DTO khusus untuk lapisan presentasi saya yang akan memiliki beberapa pengakses, bukan?
mfrachet
@ Margin Cukup banyak, ya.
Andy
Semua hal yang mengalir ini terdengar sangat bagus dan lancar, terima kasih atas jawabannya;)
mfrachet
2

Satu arah untuk berpikir adalah untuk menyediakan fungsi anggota pemformatan string generik, daripada menyediakan akses ke data mentah. Sesuatu seperti ini:

String lastName = user.formatDescription("$(Lastname)");
String fullName = user.formatDescription("$(Lastname), $(Firstname)");
String abbreviated = user.formatDescription("$(FnAbb). $(LnAbb).");

Anda lihat, dengan pendekatan ini, Anda tidak dibatasi hanya menyediakan data lengkap seperti apa adanya, Anda dapat menyediakan sarana untuk mengubah data dengan cara yang mudah dan bermakna. Misalnya, Anda mungkin perlu bermain trik dengan huruf besar-kecil:

String accountName = user.formatDescription("$(firstname).$(lastname)");

Anda juga bisa mendefinisikan beberapa format yang umum digunakan, mungkin sekali, jadi Anda bisa mengatakan, misalnya

String fullAddress = user.formatDescription(User.kAddressFormat);

Keindahan dari pendekatan ini adalah, hal itu membuat string individu internal ke Userkelas, sementara sebenarnya memberikan fungsionalitas yang lebih signifikan pada kode panggilan. Namun, downside adalah, bahwa Anda perlu menerapkan mekanisme templating di formatDescription()mana akan ada beberapa baris kode.

Dengan demikian, ini mungkin berlebihan: Jangan pernah lupa bahwa prinsip-prinsip pemrograman hanyalah panduan. Dan setiap kali mengikuti prinsip lain melanggar prinsip KISS, mungkin yang terbaik adalah melakukannya dengan cara sederhana. Jadi, kecuali Anda memiliki setidaknya beberapa kebutuhan untuk anggota pemformatan seperti itu, saya tidak akan repot-repot mengimplementasikannya demi kesederhanaan, menggunakan pendekatan berbasis pengakses.

cmaster - mengembalikan monica
sumber
5
Namun, ini terlihat seperti pelanggaran SRP bagi saya. Apakah benar-benar tanggung jawab Userobjek untuk mem-parsing dan menyusun / menafsirkan bahasa templating?
Jörg W Mittag
@ JörgWMittag Belum tentu. Seperti yang saya katakan, prinsip KISS diutamakan. Dan saya katakan di mana saja bahwa Userkelas harus mengimplementasikan fungsi ini sendiri. Jika saya hanya memiliki dua kelas yang membutuhkan fungsi seperti itu, Anda bisa bertaruh saya memasukkan mekanisme penggantian template ke dalam kelasnya sendiri. Ini dimaksudkan sebagai contoh bagaimana Anda dapat mengangkat abstraksi yang Usermenyediakan ke tingkat di mana sebenarnya lebih dari sekadar wadah data. Dan saya percaya, itulah yang menghindari aksesor: melakukan OOP daripada menangani sekelompok structs.
cmaster - mengembalikan monica
Anda tahu bahwa KISS sepenuhnya subjektif dan SRP objektif? KISS tidak memberi tahu Anda apa yang harus dilakukan. Dan apa yang "Sederhana" bagimu mungkin tidak "sederhana" bagiku. Saya melihat perbedaan nyata dalam kualitas jika berdebat dengan KISS atau SRP.
oopexpert