Collective Wisdom from the Experts 183
customersOfInterest.add(customer);
}
return customersOfInterest;
}
}
By exposing this raw collection to clients, we have violated encapsulation. This
not only limits our ability to refactor, but it also forces users of our code to vio-
late DRY by having each of them reimplement potentially the same query. This
situation can easily be avoided by removing the exposed raw collections from
the API. In this example, we can introduce a new, domain-specific collective
type called CustomerList. This new class is more semantically in line with our
domain. It will act as a natural home for all our queries.
Having this new collection type will also allow us to easily see if these queries
are a performance bottleneck. By incorporating the queries into the class, we
eliminate the need to expose representation choices, such as ArrayList, to our
clients. This gives us the freedom to alter these implementations without fear
of violating client contracts:
public class CustomerList {
private ArrayList<Customer> customers = new ArrayList<Customer>();
private SortedList<Customer> customersSortedBySpendingLevel =
new SortedList<Customer)();
// ...
public CustomerList findCustomersThatSpendAtLeast(Money amount) {
return new CustomerList(
customersSortedBySpendingLevel.elementsLargerThan(amount));
}
}
public class UsageExample {
public static void main(String[] args) {
CustomerList customers = new CustomerList();
// ...
CustomerList customersOfInterest =
customers.findCustomersThatSpendAtLeast(someMinimalAmount);
// ...
}
}
In this example, adherence to DRY allowed us to introduce an alternate index-
ing scheme with SortedList keyed on our customers’ level of spending. More
important than the specific details of this particular example, following DRY
helped us to find and repair a performance bottleneck that would have been
more difficult to find had the code been WET.