Frigör objektbeteende bortom dataåtkomst
ärTL;DR: Ta bort eller ersätta getters med beteendemässigt rika metoder som utför operationer istället för att avslöja det interna tillståndet.
är
TL;DR: Ta bort eller ersätta getters med beteendemässigt rika metoder som utför operationer istället för att avslöja det interna tillståndet.
Problem som åtgärdats
- är
- Anemiska föremål är
- Överdriven koppling är
- Förlorad inkapsling är
- Essensmutation är
- Demeters lag överträdelser är
- Informationsläckning är
- Exponerade interiörer är
- Primitiv besatthet är
Relaterad kod Luktar
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
Steg
- är
- Identifiera getter som exponerar intern objektstatus är
- Hitta alla användningsområden i codebase är
- Flytta beteende som använder getter i själva objektet är
- Skapa avsikt-avslöjar metoder som utför operationer (ta bort get prefix) är
- Uppdatera din kod för att använda de nya metoderna är
Sample kod
Före
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());
Efter
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());
Typ
- är
- [x] Halvautomatiska är
Säkerhet ️
Denna refaktorering är i allmänhet säker men kräver noggrann utförande.
Du måste se till att alla användningar av getter identifieras och ersätts med de nya beteendemetoderna.
Den största risken uppstår när getters returnerar rörliga objekt eller samlingar, eftersom klientkod kan ha modifierat dessa objekt.
Du bör kontrollera att beteendet inte har förändrats genom omfattande tester före och efter refaktorering.
För samlingar, returnera oförändrade kopior eller vyer för att upprätthålla säkerhet under övergången. För ramverk som kräver tillgång till egendom, kan du behöva bevara enkla tillbehör utan "få" prefix tillsammans med dina beteende-rika metoder.
Som vanligt bör du lägga till beteendemässig täckning (inte strukturell) till din kod innan du utför refactoring.
Varför är koden bättre?
Den omarbetade koden är bättre eftersom den följer denSäg-Fråga inteprincip, vilket gör dina objekt intelligenta snarare än bara anemiska datainnehavare.
Lösningen centraliserar logiken relaterad till objektets data inom själva objektet, vilket minskar dubbletter.Den döljer implementeringsdetaljer, så att du kan ändra intern representation utan att påverka klientkoden
Denna metod minskarKopplingsom klienter inte behöver veta om objektets interna struktur.
Det förhindrar också brott mot Demeters lag genom att eliminera kedjor av getter.
Sedan denEssensen är inte mutant, möjliggör lösningen bättre validering och verkställighet av affärsregler inom objektet.
Hur kan jag förbättra min hälsa? ️
Avlägsnande av getter förbättrarBijectionmellan kod och verklighet genom att föremål beter sig mer som sina verkliga motsvarigheter.
I den verkliga världen avslöjar objekt inte sitt inre tillstånd för andra att manipulera - de utför operationer baserat på förfrågningar.
Du frågar till exempel inte ett bankkonto om saldot och beräknar sedan själv om ett uttag är möjligt. Istället frågar du kontot, "Kan jag ta ut $100?"
Du skapar en mer trogen representation av domänkoncept genom att modellera dina objekt för att utföra operationer snarare än att exponera data.
Detta stärker en-till-en-korrespondensen mellan den verkliga världen och din beräkningsbara modell, vilket gör din kod mer intuitiv och anpassad till hur människor tänker om problemdomänen.
Denna strategi följer denkartanprincip genom att säkerställa att beräkningsobjekt speglar verkliga enheter i struktur och beteende.
Begränsningar ️
Frameworks och bibliotek förväntar sig ofta getter-metoder för serialisering/deserialisering.
Legacy codebases kan ha utbredd getter användning som är svårt att refactor alla på en gång.
Enhetstestning kan bli mer utmanande eftersom det interna tillståndet är mindre tillgängligt. Kom ihåg att du aldrig bör testa privata metoder.
Refactor med AI
ärFöreslagna prompt: 1. Identifiera getters som exponerar interna objekt tillstånd 2. Hitta alla getter användningar i kodbasen 3. Flytta beteende som använder getter i själva objektet 4. Skapa intention-revealing metoder som utför operationer (ta bort get prefix) 5. Uppdatera din kod för att använda de nya metoderna
är
Föreslagna prompt: 1. Identifiera getters som exponerar interna objekt tillstånd 2. Hitta alla getter användningar i kodbasen 3. Flytta beteende som använder getter i själva objektet 4. Skapa intention-revealing metoder som utför operationer (ta bort get prefix) 5. Uppdatera din kod för att använda de nya metoderna
Utan rätt instruktioner
Med särskilda instruktioner
Chattar
Chattar
Claude är
Claude är
förvirring
förvirring
Barnpilot
Tvillingar
djupt sökande
djupt sökande
Målet för AI
Målet för AI
Grekiska
Grekiska
Grekiska
Kvinna
Dagar ️
- är
- Encapsulering är
Nivå
- är
- [x] Medelstora är
Relaterade reaktioner
Så här
Krediter
Bild frånKrissärfrån Pixabay
Denna artikel är en del av Refactoring-serien.