模拟自动售货机的找零程序。需求描述如下:
1、程序根据用户投入货币的面额及其数量,在扣除购买的商品价额后,进行找零。
2、程序需要根据售货机内现存的各种货币面额和数量,在优先分配大面额货币的条件下,进行找零。
3、暂时仅支持整数找零。
4、实际的自动售货机找零是串行化操作,因此不考虑多线程同步问题。
package org.tang.change; /** * 货币枚举类 * @author Tang * */ public enum Currency { /** * 货币面额 */ HUNDRED_YUAN(100), FIFTY_YUAN(50), TWENTY_YUAN(20), TEN_YUAN(10), FIVE_YUAN(5), ONE_YUAN(1); /** * 货币面额值 */ private int value; public int getValue() { return value; } private Currency(int value){ this.value = value; } }
定义货币面额的枚举类。在需要增加面额情况下,可以扩展词枚举类。但是需要保证按照面额降序排列,这是为了实现较大面额货币将被优先分配找零的目的。
package org.tang.change; import java.util.HashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * 自动售货机类 * @author Tang * */ public class VendingMachine { private static final VendingMachine MACHINE = new VendingMachine(); /** * key表示货币面额 * value表示该面额货币在此售货机当中的存量 */ private static Map<Currency, Integer> moneyPool = new HashMap<Currency, Integer>(); private static Log logger = LogFactory.getLog(VendingMachine.class); static { initMoneyPool(); } private VendingMachine(){} /** * 返回自动售货机实例 * @return */ public static VendingMachine getInstance(){ return MACHINE; } /** * 初始化零钱库存 */ private static void initMoneyPool(){ moneyPool.put(Currency.ONE_YUAN, 4); moneyPool.put(Currency.FIVE_YUAN, 8); moneyPool.put(Currency.TEN_YUAN, 5); moneyPool.put(Currency.TEN_YUAN, 5); moneyPool.put(Currency.TWENTY_YUAN, 3); moneyPool.put(Currency.FIFTY_YUAN, 2); moneyPool.put(Currency.HUNDRED_YUAN, 0); if(logger.isInfoEnabled()){ logger.info("初始化售货机零钱库量:"+getStockBalance()); } } /** * 将收到的钱放入零钱库 */ private void put(Map<Currency,Integer> putMap){ if(logger.isInfoEnabled()){ logger.info("put操作前零钱库存量:"+getStockBalance()); } for(Map.Entry<Currency, Integer> entry : putMap.entrySet()){ Integer count = moneyPool.get(entry.getKey()); moneyPool.put(entry.getKey(),(count == null ? 0:count) + entry.getValue()); } if(logger.isInfoEnabled()){ logger.info("put操作后零钱库存量:"+getStockBalance()); } } /** * 从零钱库中取出若干零钱 * @param takeMap */ private void take(Map<Currency,Integer> takeMap){ if(logger.isInfoEnabled()){ logger.info("take操作前零钱库存量:"+getStockBalance()); } for(Map.Entry<Currency, Integer> entry : takeMap.entrySet()){ Integer count = moneyPool.get(entry.getKey()); moneyPool.put(entry.getKey(),(count == null ? 0:count) - entry.getValue()); } if(logger.isInfoEnabled()){ logger.info("take操作后零钱库存量:"+getStockBalance()); } } /** * 返回当前库中零钱总额 * @return */ public static int getStockBalance() { return Currency.ONE_YUAN.getValue() * moneyPool.get(Currency.ONE_YUAN) + Currency.FIVE_YUAN.getValue() * moneyPool.get(Currency.FIVE_YUAN) + Currency.TEN_YUAN.getValue() * moneyPool.get(Currency.TEN_YUAN) + Currency.TWENTY_YUAN.getValue() * moneyPool.get(Currency.TWENTY_YUAN) + Currency.FIFTY_YUAN.getValue() * moneyPool.get(Currency.FIFTY_YUAN) + Currency.HUNDRED_YUAN.getValue() * moneyPool.get(Currency.HUNDRED_YUAN); } /** * 找零钱 * @return */ public Map<Currency,Integer> giveChange(int cost, Map<Currency,Integer> putMap) { if(putMap == null){ throw new NullPointerException(); } int putAmount = getPutAmount(putMap); int payAmount = putAmount - cost; if(logger.isInfoEnabled()){ logger.info("您需要为商品支付"+cost+"元,现收您"+putAmount+"元,还需找您"+payAmount+"元。"); } if(cost <= 0 || putAmount == 0 || payAmount < 0){ throw new IllegalArgumentException("您的入参错误"); } put(putMap); Map<Currency,Integer> rtMap = new HashMap<Currency,Integer>(2); for(Currency cur : Currency.values()){ if(payAmount == 0){ break; } Integer count = moneyPool.get(cur); if(count == null){ continue; } if(payAmount - cur.getValue() == 0){ rtMap.put(cur, 1); payAmount = 0; break; } if(payAmount - cur.getValue() > 0 && payAmount / cur.getValue() > 0 && count >= (payAmount / cur.getValue())){ rtMap.put(cur, payAmount / cur.getValue()); payAmount = payAmount % cur.getValue(); } } if(payAmount != 0){ take(putMap); throw new IllegalStateException("自动售货机零钱不够了。。。您的钱将自动退还"); } take(rtMap); return rtMap; } /** * 返回收到的总金额 * @return */ private int getPutAmount(Map<Currency,Integer> putMap){ if(putMap == null || putMap.isEmpty()){ return 0; } int val = 0; for(Map.Entry<Currency,Integer> entry : putMap.entrySet()){ val += entry.getKey().getValue()*entry.getValue(); } return val; } }
package org.tang.change; import java.util.HashMap; import java.util.Map; public class Client { /** * @param args */ public static void main(String[] args) { Map<Currency,Integer> map = new HashMap<Currency,Integer>(); //投入售货机1张50元钞 map.put(Currency.FIFTY_YUAN, 1); //需要为商品支付金额 int cost = 31; VendingMachine machine = VendingMachine.getInstance(); Map<Currency,Integer> rtMap = machine.giveChange(cost,map); System.out.println("\r自动售货机找零情况如下:"); for(Map.Entry<Currency, Integer> entry : rtMap.entrySet()){ System.out.println(entry.getValue()+"张"+entry.getKey().getValue()+"元"); } } }
INFO 2012-10-23 20:10:35,718 org.tang.change.VendingMachine: 初始化售货机零钱库量:254 INFO 2012-10-23 20:10:35,720 org.tang.change.VendingMachine: 您需要为商品支付30元,现收您50元,还需找您20元。 INFO 2012-10-23 20:10:35,721 org.tang.change.VendingMachine: put操作前零钱库存量:254 INFO 2012-10-23 20:10:35,721 org.tang.change.VendingMachine: put操作后零钱库存量:304 INFO 2012-10-23 20:10:35,722 org.tang.change.VendingMachine: take操作前零钱库存量:304 INFO 2012-10-23 20:10:35,722 org.tang.change.VendingMachine: take操作后零钱库存量:284 自动售货机找零情况如下: 1张20元