Smell Detail

Feature Envy

依恋情结

Couplers

A method is more interested in the data of other classes than the data of its own class.

Define

Introduction

Feature Envy occurs when a method frequently accesses the data of other classes while using little of its own class's data. This suggests the method probably belongs elsewhere.

Key Identifiers

  • The method heavily uses data from other classes
  • The method rarely uses its own class's fields
  • High coupling between the method and foreign classes
  • Violates the principle that data and behavior should live together

Refactoring Suggestions

  1. Move Method: Move the method to the class whose data it cares about most
  2. Extract Method: Extract parts of the logic into more appropriate classes
  3. Introduce Parameter Object: Create a new class to group related data
  4. Align Data and Behavior: Keep related state and operations together

Explanation

The getCustomerAddressInfo method should be moved to the Address class because it primarily operates on Address data. This raises cohesion and reduces coupling.

Code Example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
class Customer {
private String name;
private Address address;
public String getName() { return name; }
public Address getAddress() { return address; }
public void setName(String name) { this.name = name; }
public void setAddress(Address address) { this.address = address; }
}
class Address {
private String street;
private String city;
private String zipCode;
private String country;
public String getStreet() { return street; }
public String getCity() { return city; }
public String getZipCode() { return zipCode; }
public String getCountry() { return country; }
public void setStreet(String street) { this.street = street; }
public void setCity(String city) { this.city = city; }
public void setZipCode(String zipCode) { this.zipCode = zipCode; }
public void setCountry(String country) { this.country = country; }
}
class Invoice {
private Customer customer;
private double amount;
// This method is more interested in Address class data
public String getCustomerAddressInfo() {
Address addr = customer.getAddress();
return addr.getStreet() + ", " +
addr.getCity() + " " +
addr.getZipCode() + ", " +
addr.getCountry();
}
// This method also primarily uses Customer data
public String getCustomerSummary() {
Address addr = customer.getAddress();
return "Customer: " + customer.getName() +
" from " + addr.getCity() + ", " + addr.getCountry();
}
public double getAmount() { return amount; }
public void setAmount(double amount) { this.amount = amount; }
public Customer getCustomer() { return customer; }
public void setCustomer(Customer customer) { this.customer = customer; }
}