下面给出源代码,其中有自己的一些理解注释:
conf.properties: 定义用户套餐业务价格字符串前缀
#为了便于程序编写,在配置文件中要注意如下两点:
# 1.由于程序中要求每次传输的数据量都是10k的整数倍,因此可以将数据通信费的单价单位由M转换成K表示,由于数据通信费的价格5元/M,转换后则是0.5分/K,这样程序中就涉及到小数处理了。由于在程序中处理小数是很繁琐和容易出现误差的事情,所以,最好还是想办法先统一转换成整数形式进行处理,由于数据传输量都是10k的整数倍,因此,想到将数据通信费的价格5元/M转换成5分/10K。因此,在配置文件中将所有的价格和费用的计量单位由元转换成分表示。
# 2.后来在配置文件中填写各项数据时,发现VIP用户订购套餐2时的数据费仅为0.5元/M,这时候转换的结果是0.5分/10k,又还是出现了小数,故想到把计费单位转成5厘/10k,所以,在配置文件中最终还是应将所有的价格和费用的计量单位由元转换成厘进行计费。
# 钱的单位是厘,一分十厘
common.normal.phone.price=600
common.normal.message.price=100
common.normal.data.price=50
#订购套餐后的各功能相应收费
common.pack1.phone.price=500
common.pack1.message.price=100
common.pack1.data.price=30
#套餐月功能费
common.pack1.phone.rent=20000
common.pack1.message.rent=10000
common.pack1.data.rent=20000
#套餐免费的部分
common.pack1.phone.free=60
common.pack1.message.free=200
common.pack1.data.free=5000
#vip用户的基本资费
vip.normal.phone.price=400
vip.normal.message.price=100
vip.normal.data.price=30
#vip 套餐1
vip.pack1.phone.price=300
vip.pack1.message.price=100
vip.pack1.data.price=10
#套餐免费的部分
vip.pack1.phone.free=750
vip.pack1.message.free=200
vip.pack1.data.free=10000
#vip 套餐2
vip.pack2.phone.price=200
vip.pack2.message.price=100
vip.pack2.data.price=5
#套餐免费的部分
vip.pack2.phone.free=2000
vip.pack2.message.free=500
vip.pack2.data.free=30000
#新入网普通用户 60分钟
common.new.phone.free=60
common.new.message.free=200
common.new.data.free=5000
vip.new.phone.free=200
vip.new.message.free=200
vip.new.data.free=10000
ConfigManager:
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ConfigManager {
private static Properties config = new Properties();
private ConfigManager() {}
static {
InputStream ips = ConfigManager.class.getResourceAsStream("conf.properties");
try {
config.load(ips);
} catch (IOException e) {
e.printStackTrace();
}
}
//获取前缀
private static String makePrefix(int customerType, int packType, int businessType) {
String customerTitle = customerType==0?"common.":"vip.";
String packTitle = packType==0?"normal.":("pack"+packType+".");
String businessTitle = businessType==0?"phone.":businessType==1?"message.":"data.";
return customerTitle + packTitle + businessTitle;
}
//前缀 对应的价格
private static int getNumber(String key) {
String value = config.getProperty(key);
System.out.println("--------------key---------------"+key+"---------"+value);
try {
return Integer.parseInt(value);
} catch (Exception e) {
return 0;
}
}
public static int getPrice(int customerType, int packType, int businessType) {
return getNumber(makePrefix(customerType, packType, businessType)+"price");
}
public static int getFree(int customerType, int packType, int businessType) {
return getNumber(makePrefix(customerType, packType, businessType)+"free");
}
public static int getRent(int customerType, int packType, int businessType) {
return getNumber(makePrefix(customerType, packType, businessType)+"rent");
}
//新入网用户 免费的部分 数量 前缀 注意加点
public static int getNewCustomerFree(int customerType, int businessType) {
String[] businesses = {"phone","message","data"};
return getNumber((customerType==0?"common":"vip")+".new."+businesses[businessType]+".free");
}
}
DateUtil:
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtil {
public static String formatDateToMonth(Date date){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月");
String result = sdf.format(date);
return result;
}
public static String formatDateToDay(Date date){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
String result = sdf.format(date);
return result;
}
}
PackStrategy :
import java.util.Date;
public class PackStrategy {
private int customerType;//用户类型
private int packType = 0; //套餐类型
private ComputeStrategy[] currentStrategies = new ComputeStrategy[3];
private Rent rent;
//预定套餐
private OrderedStrategyHolder<ComputeStrategy> orderedStrategies[] = new OrderedStrategyHolder[] {
new OrderedStrategyHolder<ComputeStrategy>(),
new OrderedStrategyHolder<ComputeStrategy>(),
new OrderedStrategyHolder<ComputeStrategy>(),
};
private OrderedStrategyHolder<Rent> orderedRent = new OrderedStrategyHolder<Rent>();
public PackStrategy(int customerType,int packType,Rent rent){
this.customerType = customerType;
this.packType = packType;
this.rent = rent;
for(int i=0;i<3;i++){
currentStrategies[i] = new ComputeStrategy(customerType, packType,i);
}
}
public Rent getValidRent(Date month){
Rent validRent = orderedRent.getValidComputeStrategy(month);
return validRent==null?rent:validRent;
}
public void orderRent(Date orderedMonth,Rent rent){
Rent oldRent = orderedRent.order(orderedMonth, rent);
if(oldRent != null){
this.rent = oldRent;
}
}
public void cancelRent(Date orderedMonth,Rent rent){
orderRent(orderedMonth,null);
}
public ComputeStrategy getValidPhonePack(Date currentMonth) {
ComputeStrategy computeStrategy = (ComputeStrategy)orderedStrategies[0].getValidComputeStrategy(currentMonth);
return computeStrategy==null?currentStrategies[0]:computeStrategy;
}
public ComputeStrategy getValidMessagePack(Date currentMonth) {
ComputeStrategy computeStrategy = (ComputeStrategy)orderedStrategies[1].getValidComputeStrategy(currentMonth);
return computeStrategy==null?currentStrategies[1]:computeStrategy;
}
public ComputeStrategy getValidDataPack(Date currentMonth) {
ComputeStrategy computeStrategy = (ComputeStrategy)orderedStrategies[2].getValidComputeStrategy(currentMonth);
return computeStrategy==null?currentStrategies[2]:computeStrategy;
}
public void orderPhonePack(Date orderedMonth,int packType){
ComputeStrategy oldComputeStrategy = orderedStrategies[0].order(orderedMonth, new ComputeStrategy(customerType, packType, 0));
if(oldComputeStrategy != null){
this.currentStrategies[0] = oldComputeStrategy;
}
}
public void orderMessagePack(Date orderedMonth, int packType){
ComputeStrategy oldComputeStrategy = orderedStrategies[1].order(orderedMonth, new ComputeStrategy(customerType, packType, 1));
if(oldComputeStrategy != null){
this.currentStrategies[1] = oldComputeStrategy;
}
}
public void orderDataPack(Date orderedMonth, int packType){
ComputeStrategy oldComputeStrategy = orderedStrategies[2].order(orderedMonth, new ComputeStrategy(customerType, packType, 2));
if(oldComputeStrategy != null){
this.currentStrategies[2] = oldComputeStrategy;
}
}
public void cancelPhonePack(Date orderedMonth){
orderPhonePack(orderedMonth, 0);
}
public void cancelMessagePack(Date orderedMonth){
orderMessagePack(orderedMonth, 0);
}
public void cancelDataPack(Date orderedMonth){
orderDataPack(orderedMonth, 0);
}
}
OrderedStrategyHolder<T> :
import java.util.Date;
public class OrderedStrategyHolder<T> {
//订购的月份
private Date orderedMonth;
//预定的套餐计算策略
private T computeStrategy;
public T order(Date orderedMonth, T computeStrategy) {
//原先的套餐计算策略
T oldComputeStrategy = null;
//比较月份,如果相等,old--》3_1 , orderedMonth==3的情况下,在3月份再预定2套餐
//this.computeStrategy ==3_2 , old==3_1
//如果又预定了4月份的其他套餐,在3月份,那么old = 3_2,按照3月份的2套餐计费至 4月份
if(this.orderedMonth!=null && this.orderedMonth.before(orderedMonth)) {
//this.computeStrategy是上次的
oldComputeStrategy = this.computeStrategy;
}
//记录预定套餐的月份
this.orderedMonth = orderedMonth;
//这次预定的套餐,保存最新预定的套餐
this.computeStrategy = computeStrategy;
return oldComputeStrategy;
}
//拿到有效的计算策略
public T getValidComputeStrategy(Date month) {
// moth <= orderedMonth
if(this.orderedMonth!=null && !month.before(orderedMonth)){
return computeStrategy;
}
return null;
}
}
ComputeStrategy :
/**
* 如果VIP客户和common客户的不同套餐的每种服务费的算法公式区别很大,
* 而不是相同公式仅仅参数值不同的情况 那就需要为每种客户的每种套餐的每种服务方式各设计一个类。
* 下面是用一个类中有两个属性分别记住它是哪种客户和收费策略,然后根据这两个属性在properties文件
* 中去读取价格,甚至还可以再增加一个属性,来记住是哪种服务方式。
* 这里为了演示每种服务分别对应一种计算机策略的效果,所以服务方式没有采用属性,而是采用子类方式来做。
* @author ETHAN
*
*/
public class ComputeStrategy {
private int customerType;
private int packType;
private int businessType; //业务类型,电话,短信,流量
private String businessName = "";
public ComputeStrategy(int customerType, int packType, int businessType) {
super();
this.customerType = customerType;
this.packType = packType;
this.businessType = businessType;
switch(businessType) {
case 0: businessName="电话";break;
case 1: businessName="短信";break;
case 2: businessName="流量";break;
}
}
//根据使用量 计算费用
public int computeMoney(int quantity) {
int price = ConfigManager.getPrice(customerType, packType, businessType);
int freeQuantity = ConfigManager.getFree(customerType, packType, businessType);
int chargeQuantity = quantity - freeQuantity;
if(chargeQuantity<0) {
chargeQuantity = 0;
}
//每月 电话基本费用
int phoneBaseMoney = ConfigManager.getRent(customerType, packType, businessType);
System.out.println(businessName+"功能费:"+phoneBaseMoney+" 厘钱");
//实际收费
int fee = price * chargeQuantity;
System.out.println(businessName + "计价费:" + quantity + "-" + freeQuantity + "=" + chargeQuantity + ","
+ chargeQuantity + "*" + price + "=" + fee +"厘钱");
return phoneBaseMoney + fee;
}
}