Menghapus perilaku objek di luar akses data
yangTL;DR: Menghapus atau mengganti getter dengan metode yang kaya perilaku yang melakukan operasi alih-alih mengekspos keadaan internal.
yang
TL;DR: Menghapus atau mengganti getter dengan metode yang kaya perilaku yang melakukan operasi alih-alih mengekspos keadaan internal.
Masalah yang ditangani
- yang
- Anemia benda yang
- Kopling yang berlebihan yang
- Kehilangan encapsulation yang
- Mutasi inti yang
- Hukum Demeter Pelanggaran yang
- Informasi Lulusan yang
- Internal yang dipamerkan yang
- Obsesi primitif yang
Tag: kode yang berbau
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xiv
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-i-xqz3evd
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xiii
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xiv
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxix
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xiv
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xiii
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-i-xqz3evd
https://hackernoon.com/how-to-find-the-stinky-parts-of-your-code-part-xxv
Langkah
- yang
- Mengidentifikasi getter yang mengekspos keadaan objek internal yang
- Temukan semua kegunaannya di codebase yang
- Perilaku bergerak yang menggunakan getter ke dalam objek itu sendiri yang
- Membuat metode yang mengungkapkan niat yang melakukan operasi (menghapus prefix get) yang
- Perbarui kode Anda untuk menggunakan metode baru yang
Kode sampel
Sebelumnya
public class Invoice {
private List<LineItem> items;
private Customer customer;
private LocalDate dueDate;
public Invoice(Customer customer, LocalDate dueDate) {
this.customer = customer;
this.dueDate = dueDate;
this.items = new ArrayList<>();
}
public void addItem(LineItem item) {
// This is the right way
// to manipulate the internal consistency
// adding assertions and access control if necessary
items.add(item);
}
public List<LineItem> getItems() {
// You are exposing your internal implementation
// In some languages, you also open a backdoor to
// manipulate your own collection unless you return
// a copy
return items;
}
public Customer getCustomer() {
// You expose your accidental implementation
return customer;
}
public LocalDate getDueDate() {
// You expose your accidental implementation
return dueDate;
}
}
Invoice invoice = new Invoice(customer, dueDate);
// Calculate the total violating encapsulation principle
double total = 0;
for (LineItem item : invoice.getItems()) {
total += item.getPrice() * item.getQuantity();
}
// Check if the invoice is overdue
boolean isOverdue = LocalDate.now().isAfter(invoice.getDueDate());
// Print the customer information
System.out.println("Customer: " + invoice.getCustomer().getName());
Setelah ini 🙂
public class Invoice {
private List<LineItem> items;
private Customer customer;
private LocalDate dueDate;
public Invoice(Customer customer, LocalDate dueDate) {
this.customer = customer;
this.dueDate = dueDate;
this.items = new ArrayList<>();
}
public void addItem(LineItem item) {
items.add(item);
}
// Step 3: Move behavior that uses the getter into the object
public double calculateTotal() {
// Step 4: Create intention-revealing methods
double total = 0;
for (LineItem item : items) {
total += item.price() * item.quantity();
}
return total;
}
public boolean isOverdue(date) {
// Step 4: Create intention-revealing methods
// Notice you inject the time control source
// Removing the getter and breaking the coupling
return date.isAfter(dueDate);
}
public String customerInformation() {
// Step 4: Create intention-revealing methods
// You no longer print with side effects
// And coupling to a global console
return "Customer: " + customer.name();
}
// For collections, return an unmodifiable view if needed
// Only expose internal collaborators if the name
// is an actual behavior
public List<LineItem> items() {
return Collections.unmodifiableList(items);
}
// Only if required by frameworks
// or telling the customer is an actual responsibility
// The caller should not assume the Invoice is actually
// holding it
public String customerName() {
return customer.name();
}
// You might not need to return the dueDate
// Challenge yourself if you essentially need to expose it
// public LocalDate dueDate() {
// return dueDate;
// }
}
// Client code (Step 5: Update client code)
Invoice invoice = new Invoice(customer, dueDate);
double total = invoice.calculateTotal();
boolean isOverdue = invoice.isOverdue(date);
System.out.println(invoice.customerInformation());
Jenis
- yang
- [x] Semi-Otomatis yang
Keselamatan ️
Ini refactoring umumnya aman tetapi membutuhkan eksekusi yang hati-hati.
Anda perlu memastikan semua penggunaan getter diidentifikasi dan digantikan dengan metode perilaku baru.
Risiko terbesar terjadi ketika getter mengembalikan objek atau koleksi yang dapat berubah, karena kode klien mungkin telah memodifikasi objek tersebut.
Anda harus memverifikasi bahwa perilaku tidak berubah melalui tes komprehensif sebelum dan setelah refactoring.
Untuk koleksi, kembalikan salinan atau tampilan yang tidak dapat dimodifikasi untuk mempertahankan keamanan selama transisi. Untuk kerangka kerja yang membutuhkan akses properti, Anda mungkin perlu menyimpan aksesoris sederhana tanpa prefiks "get" di samping metode yang kaya perilaku Anda.
Seperti biasa, Anda harus menambahkan cakupan perilaku (bukan struktural) ke kode Anda sebelum melakukan refactoring.
Mengapa Kode Lebih Baik?
Kode refactored lebih baik karena ia mematuhiJangan tanya-tanyaPrinsipnya, membuat objek Anda cerdas dan bukan hanya pemegang data anemik.
Solusi ini menyentralisasikan logika yang terkait dengan data objek dalam objek itu sendiri, mengurangi duplikasi, menyembunyikan detail implementasi, memungkinkan Anda untuk mengubah representasi internal tanpa mempengaruhi kode klien
Pendekatan ini mengurangiKoperasiKarena klien tidak perlu tahu tentang struktur internal objek.
Ini juga mencegah pelanggaran hukum Demeter dengan menghilangkan rantai getter.
Sejak yangEsensi Tidak Bermutasi, solusi memungkinkan validasi yang lebih baik dan penegakan aturan bisnis dalam objek.
Bagaimanakah caranya untuk meningkatkan kesuburan? ️
Menghapus getter meningkatkanbiasantara kode dan realitas dengan membuat objek berperilaku lebih seperti rekan-rekan mereka di dunia nyata.
Di dunia nyata, objek tidak mengekspos keadaan internal mereka untuk orang lain untuk dimanipulasi - mereka melakukan operasi berdasarkan permintaan.
Misalnya, Anda tidak meminta rekening bank untuk saldo dan kemudian menghitung apakah penarikan dimungkinkan sendiri.
Anda membuat representasi lebih setia dari konsep domain dengan memodelkan objek Anda untuk melakukan operasi daripada mengekspos data.
Ini memperkuat korespondensi satu-ke-satu antara dunia nyata dan model komputasi Anda, membuat kode Anda lebih intuitif dan selaras dengan bagaimana orang berpikir tentang domain masalah.
Pendekatan ini mengikutiPetaprinsip dengan memastikan bahwa objek komputasi mencerminkan entitas dunia nyata dalam struktur dan perilaku.
Keterbatasan ️
Kerangka kerja dan perpustakaan sering mengharapkan metode getter untuk serialisasi / deserialisasi.
Codebases warisan mungkin memiliki penggunaan getter yang luas yang sulit untuk refactor semuanya sekaligus.
Pengujian unit dapat menjadi lebih menantang karena keadaan internal kurang dapat diakses. Ingat, Anda tidak boleh pernah menguji metode pribadi.
Reaktor dengan AI
yangPrompt yang disarankan: 1. mengidentifikasi getter yang mengekspos keadaan objek internal 2. menemukan semua penggunaan getter di basis kode 3. memindahkan perilaku yang menggunakan getter ke dalam objek itu sendiri 4. membuat metode yang mengungkapkan niat yang melakukan operasi (menghapus prefix get) 5. memperbarui kode Anda untuk menggunakan metode baru
yang
Prompt yang disarankan: 1. mengidentifikasi getter yang mengekspos keadaan objek internal 2. menemukan semua penggunaan getter di basis kode 3. memindahkan perilaku yang menggunakan getter ke dalam objek itu sendiri 4. membuat metode yang mengungkapkan niat yang melakukan operasi (menghapus prefix get) 5. memperbarui kode Anda untuk menggunakan metode baru
yangTanpa instruksi yang tepat dengan instruksi spesifik ChatGPT ChatGPT Claude Claude Perplexity Perplexity Copilot Copilot Gemini Gemini DeepSeek DeepSeek Meta AI Meta AI Grok Grok Qwen QwenTanpa instruksi yang tepat
Tanpa instruksi yang tepat
yangDengan instruksi khusus
Dengan instruksi khusus
yangChatGPTyangChatGPTyangyangChatGPT
yangChatGPT
yangClaude yangyangClaude yangyangClaude yangClaude yang
yangClaude yang
Claude yang
Perplexitas PerplexitasPersepsiPersepsi
PersepsiPilot CopilotAnak PilotyangAnak Pilot
Anak Pilot
Remaja GeminiGeminiGeminiGemini
Menggunakan DeepSeekDeepSeekyangDeepSeek
Untuk tujuan yangTarget yangyangTarget yang
Target yang
yangGokilyangGokilyangGokilGokilKemenangan QwenyangQiang
QiangTanggal ️
- yang
- Encapsulasi yang
Tingkat
- yang
- [x] yang menengah yang
Reaksi yang terkait
Lihat juga
Kredit
Gambar olehKrisadalaholeh Pixabay
Artikel ini adalah bagian dari seri Refactoring.