自动售货机的找零程序模拟

模拟自动售货机的找零程序。需求描述如下:

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元
 

你可能感兴趣的:(java,enum,枚举,自动售货机,找零)