Witajcie,
w tym poście zapoznam was z wzorcem projektowym zwanym Information Expert.
Wzorzec określa jak przydzielić odpowiedzialność klasie, która ma wykonać pewne zadanie.
We wzorcu Expert, dowiadujemy się, że klasa powinna wykonywać zadanie, o którym wie najlepiej. Czyli, klasa powinna posiadać informacje bezpośrednio "z pierwszej ręki" bez potrzeby wyciągania informacji z innych klas. Narażałoby to klasę na złamanie zasady prawa Demeter ("Nie rozmawia z nieznajomymi"), o którym napiszę w innym poście.
Załóżmy, że mamy człowieka i jego żołądek. Zastanówmy się co się stanie, kiedy człowiek coś zje. Pytanie jest takie, to "Człowiek" trawi jedzenie czy "żołądek" trawi. Możemy w sumie zrobić metodę w klasie "Człowiek" o nazwie jedz oraz metodę o nazwie przetraw. Stosując wzorzec expert, wiemy, że klasa człowiek nie ma bezpośredniej możliwości trawienia zjedzonego jedzenia. Dlatego metodę "trawienie" przerzucamy do klasy "żołądek", a metodę jedz moglibyśmy przekazać nowej klasie "buzia". Natomiast klasa człowiek powinna mieć metodę jedz, która przekazuje jedzenie do ust i tak dalej :)
Zobaczmy jak to zadziała, jeżeli przerzucimy to na kod:
public class Main {
public static void main(String[] args) {
Food food = new Food("Jabłko", 0.01);
Human human = new Human();
boolean eaten = human.eats(food);
if(eaten) {
System.out.println("Czlowiek zjadl " + food.getFoodName());
}else {
System.out.println("Czlowiekowi zaszkodzilo " + food.getFoodName());
}
}
}
public class Human {
private final Mouth mouth = new Mouth();
public boolean eats(Food food) {
return mouth.bite(food);
}
}
public class Mouth {
//Moglibysmy tutaj miec system trawienia, ale uproscilem to na potrzeby przykladu
private final Stomach stomach = new Stomach();
public boolean bite(Food food) {
return stomach.digest(food);
}
}
public class Stomach {
public boolean digest(Food food) {
return food.isProblematic();
}
}
public class Food {
private final String foodName;
private final double riskOfProblems;
private static Random random = new Random();
public Food(String foodName, double riskOfProblems) {
this.foodName = foodName;
this.riskOfProblems = riskOfProblems;
}
public String getFoodName() {
return foodName;
}
public boolean isProblematic() {
return random.nextDouble() <= riskOfProblems;
}
}
Jak widzicie, powyżej przedstawiłem skróconą wersję trawienia pewnego pożywienia. Dałem żywności pewną szansę, że będzie problem jak człowiek nią zje.
Z klas widać ewidentnie jakie klasy są ekspertami w swojej dziedzinie. Jeżeli tymi ekspertami nie są, to przekazują informacje innych klas. Na końcu, eksperci wykonują swoją robotę i prawdopodobnie zwracają jakąś informację.
Jeżeli macie fajniejsze przykłady wykorzystania tego wzorca, to napiszcie w komentarzach :)