import java.util.*; // Test code: // ---------- // ---------- class Client { static public void main(String[] args) { PricingTax t1 = new PricingTax((float)0.05); PricingTax t2 = new PricingTax((float) 0.07); PricingTax[] t = {t1, t2}; PricingHWProduct product = new PricingHWProduct("Schreibmaschine", (float) 250, (float) 200, t); PricingCustomer cust = new PricingCustomer("Schmidt", (float) 0.5, (float) 0.02); PricingQuote q = new PricingQuote(product, cust, 10); RegScheme.singleInstance().adapt(q); System.out.println(q.price()); System.out.println(q.test); // ... // Later after I have added negotiated pricing System.out.println("Changing the scheme ..."); NegScheme.singleInstance().adapt(q); System.out.println(q.price()); System.out.println(q.test); // Now adding total System.out.println("Adding the total component ..."); System.out.println("Creating a new quote and adapting to regular pricing..."); PricingQuote q2 = new PricingQuote(product, cust, 5); RegScheme.singleInstance().adapt(q2); System.out.println("Q2 reg price ... " + q2.price()); TotalAdapter.singleInstance().adapt(q); TotalAdapter.singleInstance().adapt(q2); PricingQuote[] quotes = {q, q2}; Order o = new Order(quotes); System.out.println("the total reg ..." + o.total()); System.out.println("the total neg ..." + o.total((Object) "negCollectionParty")); } } // Result: // ------- // 224.0 // Hello // Changing the scheme ... // 112.0 // Hello // Adding the total component ... // Creating a new quote and adapting to regular pricing... // Q2 reg price ... 252.0 // the total reg ...476.0 // the total neg ...238.0 // NOTE: There is an improvement to be done // As implemented here, there is only one active lineItemParty role of // a quote. Thus, before calculating the price according to one or the other scheme // an adapt method call must be done before. This can be changed. We can have // as many different lineItemParties as there are schemes. See the case with // the regElementParty and negElementParty. In this case, adapt needs to be // called only once and means "add this role to this instance". After that // the role can be used as many times as necessary without adaptation. // Among different variant of a role we can chose one to be "the default". // RegCollectionAdapter has been chosen to be the default role for Order. // This is used by total(). The other roles can be invoked explicitly. See above // o.total((Object) "negCollectionParty"). The same can be done with price(); // Having several variants of the same role can also appear for HWProduct, if we add // SalePricing. In this case, we need to adapt instances of PricingHWProduct // to play the new role. This would mean to add a new variant of the pricerParty // - salePricerParty - to the instance. // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // APPLICATION CODE // ---------------- class HWProduct { protected String name; protected float price, salePrice; protected Tax[] taxes; // protected HashTable discount; // protected Producer producer; // protected Date entered; Tax[] taxes() {return taxes;} float salePrice() {return salePrice;} float saleDiscount() {return 0;} float regPrice() {return price;} // float regDiscount(int qty) {return discount.lookup(qty);} float regDiscount(int qty) {return qty * (float) 0.02;} // Producer producer() {retrun producer;} public HWProduct() {} public HWProduct (String prodName, float pr, float salePr, Tax[] tax) { name = prodName; price = pr; salePrice = salePr; taxes = tax; } } class Tax { protected float salePercentage; // protected HashTable productCategories; float taxCharge(HWProduct prod, float unitPr, int qty) { // HashKey key = new HashKey(prod, qty); // float categPercentage = productCategories.lookup(key); // return unitPr * categPercentage * salePercentage; return unitPr * salePercentage; } public Tax(float perc) { salePercentage = perc; } } class Quote { protected HWProduct prod; protected int qty; protected Customer cust; // protected Employee enteredBy; public String test = "Hello"; // protected Date deliveryTime; // protected Date orderEntryTime; int quantity() {return qty;} HWProduct prod() {return prod;} Customer customer() {return cust;} public Quote() {}; public Quote(HWProduct product, Customer customer, int quantity) { cust = customer; prod = product; qty = quantity; } } class Customer { protected String name; // protected String address; // protected HashTable negotiatedProdPrices; protected float negotiatedProdPrices; protected float negotiatedDiscountPercentage; // float negProdPrice(HWProduct prod) { // negotiatedProdPrices.lookup((Object) prod); // } float negProdPrice(HWProduct prod) { float pr = prod.regPrice(); return (pr - pr * negotiatedProdPrices); } float negProdDiscount(HWProduct prod, int qty) { return qty * negotiatedDiscountPercentage; } String getName() {return name;} public Customer(String custName, float negProdPrices, float negDiscPerc) { name = custName; negotiatedProdPrices = negProdPrices; negotiatedDiscountPercentage = negDiscPerc; } } // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ // PRICING COMPONENT // ----------------- abstract class LineItemParty { abstract int quantity(); abstract ItemParty item(); abstract PricerParty pricer(); abstract CustomerParty customer(); public float price() { float discount; float basicPrice, unitPrice; PricerParty pricer = pricer(); CustomerParty customer = customer(); int qty = quantity(); ItemParty item = item(); basicPrice = pricer.basicPrice(item); discount = pricer.discount(item, qty, customer); unitPrice = basicPrice - (discount * basicPrice); return unitPrice + item.addCharges(unitPrice, qty); } } abstract class ItemParty { float addCharges(float unitPrice, int qty) { float total = 0; for (int i = 0; i < charges().length; i++) total += charges()[i].cost(qty, unitPrice, this); return total; } abstract ChargerParty[] charges(); } interface PricerParty { float basicPrice(ItemParty item); float discount(ItemParty item, int qty, CustomerParty cust); } interface ChargerParty { float cost (int qty, float unitPr, ItemParty item); } interface CustomerParty {} // ------------------------------------------------------------------------ // ------------------------------------------------------------------------ // Adaptation Code: // ---------------- // ---------------- interface AdapterObject { Object enclosed(); } // Abstract Scheme: // --------------- // --------------- class PricingQuote extends Quote { public java.util.Hashtable roleAdapters = new java.util.Hashtable(); public float price() { LineItemParty li = (LineItemParty) roleAdapters.get((Object) "lineItemParty"); return li.price(); } PricingHWProduct prod; PricingCustomer cust; public PricingQuote(PricingHWProduct product, PricingCustomer customer, int quantity) { super(product, customer, quantity); cust = customer; prod = product; } } class PricingHWProduct extends HWProduct { public java.util.Hashtable roleAdapters = new java.util.Hashtable(); PricingTax[] taxes; class MyItemParty extends ItemParty implements AdapterObject { public ChargerParty [] charges() { ChargerParty [] taxTable = new ChargerParty[taxes.length]; for (int i = 0; i