Вылезает ко мне в ICQ приятель и говорит: анекдот мол слышал такой?
Жена - мужу-программеру:
Сходи в магазин
Купи буханку хлеба.
Если будут яйца - купи десяток.
Муж в магазине:
- Яйца есть?
- Есть.
- Тогда дайте десять буханок хлеба!
Cлышал, говорю. А он - а запрограммируй?
Я сначала думаю - что за ерунда? А потом решил - почему бы и нет?
Вот что вышло (на коленке, в первом приближении):
public void testAnekdot() {
final Person wife = new Person();
final Person husband = new Person();
final Shop shop = new Shop();
// Жена - мужу-программеру:
final Instructions instructions = wife.instruct(husband);
// Сходи в магазин
final ShopVisit visitShop = instructions.visit(shop);
// Купи буханку хлеба.
final Buying purchaseBread = visitShop.buy(new ProductLookup() {
public Product getProduct(Shop shop) {
return shop.lookup("bread");
}
}, new IntegerQuantityLookup(1));
// Если будут яйца - купи десяток.
visitShop.getCurrentBuying().setQuantityLookup(new QuantityLookup() {
public Number getQuantity(Shop shop) {
return shop.lookup("eggs") != null ? 10 : 1;
}
});
// - Яйца есть?
// - Есть.
// - Тогда дайте десять буханок хлеба!
final Collection
purchases = instructions.execute();
Assert.assertEquals(1, purchases.size());
final Purchase purchase = purchases.iterator().next();
Assert.assertEquals("bread", purchase.getProduct().getName());
Assert.assertEquals(10, purchase.getQuantity());
}
public static class Person {
public Instructions instruct(Person person) {
return new Instructions(this, person);
}
}
public static class Instructions {
private final Person instructor;
private final Person subordinate;
private final Collection actions = new LinkedList();
public Instructions(Person instructor, Person subordinate) {
this.instructor = instructor;
this.subordinate = subordinate;
}
public Person getInstructor() {
return instructor;
}
public Person getSubordinate() {
return subordinate;
}
public ShopVisit visit(Shop shop) {
final ShopVisit shopVisit = new ShopVisit(shop);
actions.add(shopVisit);
return shopVisit;
}
public Collection
execute() {
final Collection
purchases = new LinkedList
();
for (final ShopVisit shopVisit : actions) {
purchases.addAll(shopVisit.execute());
}
return purchases;
}
}
public static class Shop {
public Product lookup(String productName) {
// У нас типа все есть!
return new Product(productName);
}
public Purchase sell(Product product, Number quantity) {
// И в любых количествах!
return new Purchase(product, quantity);
}
}
public static class ShopVisit {
private final Shop shop;
private final Collection buyings = new LinkedList();
public ShopVisit(Shop shop) {
this.shop = shop;
}
public Collection
execute() {
final Collection
purchases = new LinkedList
();
for (Buying buying : buyings) {
purchases.add(buying.execute(shop));
}
return purchases;
}
private Buying currentBuying;
public Buying getCurrentBuying() {
return currentBuying;
}
public Buying buy(ProductLookup productLookup,
QuantityLookup quantityLookup) {
final Buying buying = new Buying(productLookup, quantityLookup);
buyings.add(buying);
this.currentBuying = buying;
return buying;
}
}
public static class Buying {
private final ProductLookup productLookup;
private QuantityLookup quantityLookup;
public Buying(ProductLookup productLookup, QuantityLookup quantityLookup) {
this.productLookup = productLookup;
this.quantityLookup = quantityLookup;
}
public ProductLookup getProductLookup() {
return productLookup;
}
public QuantityLookup getQuantityLookup() {
return quantityLookup;
}
public void setQuantityLookup(QuantityLookup quantityLookup) {
this.quantityLookup = quantityLookup;
}
public Purchase execute(Shop shop) {
final Product product = productLookup.getProduct(shop);
final Number quantity = quantityLookup.getQuantity(shop);
return shop.sell(product, quantity);
}
}
public static class Purchase {
private final Product product;
private final Number quantity;
public Purchase(Product product, Number quantity) {
this.product = product;
this.quantity = quantity;
}
public Product getProduct() {
return product;
}
public Number getQuantity() {
return quantity;
}
}
public static class Product {
private final String name;
public Product(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public interface ProductLookup {
public Product getProduct(Shop shop);
}
public interface QuantityLookup {
public Number getQuantity(Shop shop);
}
public static class IntegerQuantityLookup implements QuantityLookup {
private final int quantity;
public IntegerQuantityLookup(final int quantity) {
this.quantity = quantity;
}
public Number getQuantity(Shop shop) {
return quantity;
}
}
Про потенциальные NPE и т.п. я в курсе. :)