But when you make this concept your guiding principal, you tend to write code which enforces strict client behavior. Invariably, you end up writing components that are almost unusable with changing requirements. When you get hell bent on using the component, either
1. you modify existing code breaking the very first principal of object oriented programming - entities must be closed to modification but open to extension. As one guy in my team puts it, your SVN revision must only have 'A's and almost zero 'M's.
2. or write infinitely complex super-generic code which is a nightmare to maintain and is uber-hard to understand
Here's a concrete example. Assume you need to maintain a list of animals. Your clients hold another animal. They need to check if the animal is dangerous or not. Religiously following the concept of encapsulation, you might come up with -
Clearly, this models the present but not the future. Another implementation could be -
public enum Animal {
TIGER (Category.DANGEROUS);
LEOPARD (Category.DANGEROUS);
DOG (Category.FUN);
CAT (Category.DISGUSTING);
GODZILLA (Category.OH_MY_GOD);
private Category category;
public Animal (Category category) {
this.category = category;
}
// I will not allow people to see what category assignments
// I've made. It might offend them!
private Category getCategory() {
return this.category;
}
public static boolean isAnimalOfCategory(Category category) {
for (Animal a : EnumSet.allOf(Animal) {
if (a.getCategory().equals(category)) return true;
}
return false;
}
}
I might also write a fancy method which given a Category would return a List of all animals I have for that category, but I'll pass. The second method enforces a logical grouping of all animals in the sample space which is also one of the objectives of the entity. The second class breaks encapsulation but lets you answer the following easily-
public enum Animal {
TIGER (Category.DANGEROUS);
LEOPARD (Category.DANGEROUS);
DOG (Category.FUN);
CAT (Category.DISGUSTING);
GODZILLA (Category.OH_MY_GOD);
private Category category;
public Animal (Category category) {
this.category = category;
}
// But I'll let them know what all I have for a
// particular type and let them do whatever they want with it.
public static List<Animal> getAllDangerousOnes() {
return Arrays.asList(Animal.TIGER, Animal.LEOPARD);
}
}
1. Is animal of category X?
2. Give me all animals of category Y.
3. Give me all animals but not of category Z.
A quirky tidbit but I it liked so much that I wanted to put it up here. Leave a comment if you think there are better solutions.
Khuda Hafiz,
Sultan of Samarkand
