- 浏览: 29055 次
- 性别:
- 来自: 深圳
最新评论
-
ZMC330:
明年我也即将毕业了,学长的经历看了获益不少,我实习差不多一年了 ...
工作第一年 -
p4nny:
18行代码变44行代码了
用“主线+事件”的方式来编写代码 -
raoliv:
这个贴应该发到jdon去。
用“主线+事件”的方式来编写代码 -
Saito:
这样的写法是很冗余的,你需要的其实是一个state-machi ...
用“主线+事件”的方式来编写代码 -
luzhecheng:
sing100star 写道
2、add Listener( ...
用“主线+事件”的方式来编写代码
1、 配额管理模块设计的思路:
a、引入账户模型。通过引入账户模型,可以通过控制配额账户的活动,我们可以允许透支,可以规定额度,也可以冻结其账户。另外系统可以追溯配额的使用情况,来龙去脉。
b、引入生产者和消费者模型。配额的产生和配额的使用是两个不同的活动。我把前一种活动产生的配额叫生产配额,后一种叫消费配额。
生产配额是有期限的,过期的生产配额是无法使用的,同时生产配额必须记录它已经使用了多少配额,这通过持有消费配额的集合 来达到目的。
与此相反,消费配额没有有效期,但是它必须记录配额在什么时候被使用。
通过这种方式,可以计算某个消费配额的剩余额度,也容易地作废某些过期配额。
2、集体实现
首先是 QuotaEntery(配额条目),做为配额增加、减少、使用、调整、作废等情况的。
/** * 配额条目 */ public class QuotaEntry { /** 项目类型*/ protected QuotaEntryType entryType; /** 额度,可正,可负 */ protected int amount; /** 创建时间*/ private Date createTime; protected QuotaAccount account; public QuotaEntryType getEntryType() { return entryType; } public void setEntryType(QuotaEntryType entryType) { this.entryType = entryType; } public int getAmount() { return amount; } public void setAmount(int amount) { this.amount = amount; } public QuotaAccount getAccount() { return account; } public void setAccount(QuotaAccount account) { this.account = account; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } }
其次是ConsumeQuotaEntry(消费者)和ProduceQuotaEntry(生产者)。他们继承QuotaEntry,不同的是ProdcuceQuotaEntry记录配额的产生,ConsumeQuotaEntry则是记录配额的减少,
/** * 生产配额 条目 */ public class ProduceQuotaEntry extends QuotaEntry implements Comparable<ProduceQuotaEntry>{ /** * 有效期 */ public static int DEFALUT_LIFE_YEAR = 2; /** * 配额的有效期 */ private Date beginTime; private Date endTime; private List<ConsumeQuotaEntry> consumeEntries = new ArrayList<ConsumeQuotaEntry>(10); public Date getBeginTime() { return beginTime; } public void setBeginTime(Date beginTime) { this.beginTime = beginTime; } public Date getEndTime() { return endTime; } public void setEndTime(Date endTime) { this.endTime = endTime; } /** * 是否是可用的配额条目 */ public boolean isUsable() { Date current = new Date(); return current.getTime() >= beginTime.getTime() && current.getTime() <= endTime.getTime() && caclRemainQuota() > 0; } /** * 是否是过期的配额 * @return */ public boolean isOverdue(){ return new Date().getTime() > endTime.getTime(); } /** * 计算当前条目剩下可用的配额 * @return */ public int caclRemainQuota(){ int used = 0; for(ConsumeQuotaEntry entry:consumeEntries){ used += entry.getAmount(); } return amount + used; } public int compareTo(ProduceQuotaEntry o) { if(this.getEndTime().getTime() > o.getEndTime().getTime()){ return 1; } if(this.getEndTime().getTime() < o.getEndTime().getTime()){ return -1; } return 0; } public void addConsumeEntry(ConsumeQuotaEntry consume) { consumeEntries.add(consume); consume.setProduce(this); } }
/** * 消费配额 */ public class ConsumeQuotaEntry extends QuotaEntry { /**减少配额 所依据的 消费配额额 */ private ProduceQuotaEntry produce; public ProduceQuotaEntry getProduce() { return produce; } public void setProduce(ProduceQuotaEntry produce) { this.produce = produce; } }
QuotaEntryType,枚举类,记录 导致配额增加,减少的业务种类
public enum QuotaEntryType { TransferFrom, //转入 TransferTo, //转出 Deduct, //扣减 Restore, //归还 Init, //初始 Decrease, //减少 Increase, //增加 Repeal; //作废 }
QuotaEntryFactory,配额条目工厂,屏蔽创建配额条目的细节
public class QuotaEntryFactory { /** * 返回 过期作废的配额条目 * @param amount * @return */ public static ConsumeQuotaEntry getRepealEntry(int amount) throws QuotaException { return getReducedEntry(amount,QuotaEntryType.Repeal); } /** * 返回 转出的 配额 * @param amount * @return * @throws QuotaException */ public static ConsumeQuotaEntry getTransferToEntry(int amount) throws QuotaException { return getReducedEntry(amount,QuotaEntryType.TransferTo); } /** * 返回 扣减的配额 * @param amount * @return * @throws QuotaException */ public static ConsumeQuotaEntry getDeductEntry(int amount) throws QuotaException { return getReducedEntry(amount,QuotaEntryType.Deduct); } /** * 返回 减少的配额 * @param amount * @return * @throws QuotaException */ public static ConsumeQuotaEntry getDecreaseEntry(int amount) throws QuotaException { return getReducedEntry(amount,QuotaEntryType.Decrease); } /** * 返回 归还的配额 * @param consume * @return * @throws QuotaException */ public static ConsumeQuotaEntry getRestoreEntry(ConsumeQuotaEntry consume) throws QuotaException { ConsumeQuotaEntry newConsume = new ConsumeQuotaEntry(); newConsume.setEntryType(QuotaEntryType.Restore); newConsume.setAmount(-consume.getAmount()); newConsume.setCreateTime(new Date()); return newConsume; } public static ConsumeQuotaEntry getReducedEntry(int amount,QuotaEntryType type) throws QuotaException { check(amount); ConsumeQuotaEntry consume = new ConsumeQuotaEntry(); consume.setEntryType(type); consume.setCreateTime(new Date()); consume.setAmount(-amount); return consume; } public static ProduceQuotaEntry getInitEntry(int amount) throws QuotaException { check(amount); return getRaisedEntry(amount,QuotaEntryType.Init); } public static ProduceQuotaEntry getIncreaseQuotaEntry(int amount) throws QuotaException { check(amount); return getRaisedEntry(amount,QuotaEntryType.Increase); } public static ProduceQuotaEntry getTransferFromEntry(int amount) throws QuotaException { check(amount); return getRaisedEntry(amount,QuotaEntryType.TransferFrom); } public static ProduceQuotaEntry getRaisedEntry(int amount,QuotaEntryType type){ ProduceQuotaEntry entry = new ProduceQuotaEntry(); entry.setEntryType(type); Calendar c = Calendar.getInstance(); entry.setBeginTime(c.getTime()); c.add(Calendar.YEAR, ProduceQuotaEntry.DEFALUT_LIFE_YEAR); entry.setEndTime(c.getTime()); entry.setAmount(amount); entry.setCreateTime(new Date()); return entry; } private static void check(int amount) throws QuotaException { if (amount < 0) throw new QuotaException(QuotaMsg.QuotaMustBeMoreThanZero.getName()); } }
QuotaException(配额异常消息类)
public class QuotaException extends Exception { public QuotaException(String s) { super(s); } }
QuotaMsg(各种异常消息)
public enum QuotaMsg { AccountHasBeenFrozen { public String getName() { return "账户已被冻结"; } }, AccountCantBeOverDraft { public String getName() { return "账户不可透支"; } }, ItHasBeyondLimitQuota { public String getName() { return "已经超过透支额度"; } }, QuotaMustBeMoreThanZero { public String getName() { return "配额必须大于0"; } }, AnAccountOnlyHasAnInitEntry { public String getName() { return "一个账户只有一条Init记录"; } }; public abstract String getName(); }
QuotaAccount,业务逻辑发生的地方
/** * 配额账户.. */ public class QuotaAccount { /** 账户名称 */ private String name; /** 是否冻结 */ private boolean frozen; /** 是否可以透支 */ private boolean overdrawn; /** 透支额度 */ private Long limit; /** 配额条目 */ private List<QuotaEntry> quotaEntries = new ArrayList<QuotaEntry>(16); /** * 购买商品后,扣减配额 * @param amount 额度 */ public List<ConsumeQuotaEntry> deduct(int amount) throws QuotaException { checkAccount(amount); //可用的生产配额 List<ProduceQuotaEntry> avaiEntries = findAvaiEntry(); //生成的消费配额 List<ConsumeQuotaEntry> consumeList = reduceQuota(avaiEntries,amount,QuotaEntryType.Deduct); return consumeList; } /** * 计算剩余配额 * @return */ public int caclOddQuota(){ int count = 0; for(QuotaEntry entry:quotaEntries){ count += entry.getAmount(); } return count; } /** * 归还配额 * @param consume 消费配额 * @throws QuotaException */ private void restore(ConsumeQuotaEntry consume) throws QuotaException { //1、找到对应的生产积分条目 ProduceQuotaEntry produce = consume.getProduce(); //2、生成一条 归还条目 ConsumeQuotaEntry newConsume = QuotaEntryFactory.getRestoreEntry(consume); //3、把积分写到指定生产配额下 produce.addConsumeEntry(newConsume); //4、添加到账户下 addQuotaEntry(newConsume); } /** * 归还配额 * @param consumeList 消费条目列表 * @throws QuotaException */ public void restore(List<ConsumeQuotaEntry> consumeList) throws QuotaException { for(ConsumeQuotaEntry consume:consumeList){ restore(consume); } } /** * 作废生产配额 * @param produce 生产配额 * @return * @throws QuotaException */ public ConsumeQuotaEntry repeal(ProduceQuotaEntry produce) throws QuotaException { int remain = produce.caclRemainQuota(); ConsumeQuotaEntry consume = QuotaEntryFactory.getRepealEntry(remain); produce.addConsumeEntry(consume); addQuotaEntry(consume); return consume; } /** * 作废所有过期的配额 * @return */ public void repeal() throws QuotaException { for(QuotaEntry entry:quotaEntries) { if(ProduceQuotaEntry.class.isInstance(entry)){ ProduceQuotaEntry produce = (ProduceQuotaEntry)entry; if(produce.isOverdue() && produce.caclRemainQuota() > 0){ repeal(produce); } } } } /** * 把 一定数量的配额 转移到 另一个账户上 * * @param account 目标账户 * @param amount 额度 * @throws QuotaException */ public void transferTo(QuotaAccount account, int amount) throws QuotaException { checkAccount(amount); List<ProduceQuotaEntry> avaiEntries = findAvaiEntry(); List<ConsumeQuotaEntry> consumeList= reduceQuota(avaiEntries,amount,QuotaEntryType.TransferTo); account.transferFrom(consumeList); } /** * 接收 从某个账户转移过来的额度 * */ public void transferFrom(List<ConsumeQuotaEntry> consumeList) throws QuotaException { int amount = 0; for(ConsumeQuotaEntry consume:consumeList){ amount += consume.getAmount(); } amount = Math.abs(amount); transferFrom(amount); } private void transferFrom(int amount) throws QuotaException { ProduceQuotaEntry produce = QuotaEntryFactory.getTransferFromEntry(amount); addQuotaEntry(produce); } /** * 增加 配额 * * @param amount */ public ProduceQuotaEntry increaseQuota(int amount) throws QuotaException { ProduceQuotaEntry produce = QuotaEntryFactory.getIncreaseQuotaEntry(amount); addQuotaEntry(produce); return produce; } /** * 减少 配额 * produce 生产配额 * @param amount */ public void decreaseQuota(ProduceQuotaEntry produce,int amount) throws QuotaException { checkAccount(amount); if(produce.caclRemainQuota() <amount) throw new QuotaException("生产配额少于消费配额"); ConsumeQuotaEntry consume = QuotaEntryFactory.getDeductEntry(amount); addQuotaEntry(consume); } /** * 找到可用的配额账目 * @return */ private List<ProduceQuotaEntry> findAvaiEntry(){ List<ProduceQuotaEntry> avaiEntries = new ArrayList<ProduceQuotaEntry>(10); for(QuotaEntry entry:quotaEntries){ if(!ProduceQuotaEntry.class.isInstance(entry)) break; ProduceQuotaEntry produce = (ProduceQuotaEntry) entry; if(produce.caclRemainQuota() > 0 && produce.isUsable()){ avaiEntries.add(produce); } } Collections.sort(avaiEntries); return avaiEntries; } /** * 创建初始配额账户 * * @param amount */ public void init(int amount) throws QuotaException { if (hasInitEntry()) throw new QuotaException(QuotaMsg.AnAccountOnlyHasAnInitEntry.getName()); addQuotaEntry(QuotaEntryFactory.getInitEntry(amount)); } public boolean hasInitEntry() { boolean has = false; for (QuotaEntry entry : quotaEntries) { if (entry.getEntryType().equals(QuotaEntryType.Init)) { has = true; break; } } return has; } /** * 从一群 可用的而生产配额中,减去 配额 * @param avaiEntries * @param amount * @return 扣减记录 * @throws QuotaException */ private List<ConsumeQuotaEntry> reduceQuota(List<ProduceQuotaEntry> avaiEntries,int amount,QuotaEntryType type) throws QuotaException { List<ConsumeQuotaEntry> consumeList= new ArrayList<ConsumeQuotaEntry>(4); int remain =amount; int toReduce = amount; Iterator<ProduceQuotaEntry> iterator = avaiEntries.iterator(); while(iterator.hasNext()){ ProduceQuotaEntry produce = iterator.next(); remain -= produce.caclRemainQuota(); ConsumeQuotaEntry consume= null; //如果还没有扣完,而且还有配额条目 if(remain > 0 && iterator.hasNext()){ consume = QuotaEntryFactory.getReducedEntry(produce.getAmount(),type); toReduce = amount - produce.getAmount(); //如果没有扣完,也没有其他配额条目, }else if(remain > 0 && !iterator.hasNext()){ consume = QuotaEntryFactory.getDeductEntry(toReduce); }else if(remain <= 0){ consume = QuotaEntryFactory.getDeductEntry(toReduce); } produce.addConsumeEntry(consume); addQuotaEntry(consume); consumeList.add(consume); } return consumeList; } /** * 检验配额是是否足够 * @param amount * @throws QuotaException */ private void checkAccount(int amount) throws QuotaException { if (isFrozen()) throw new QuotaException(QuotaMsg.AccountHasBeenFrozen.getName()); if (!isOverdrawn() && caclOddQuota() < amount) throw new QuotaException(QuotaMsg.AccountCantBeOverDraft.getName()); if (isOverdrawn() && (caclOddQuota() + limit < amount)) throw new QuotaException(QuotaMsg.ItHasBeyondLimitQuota.getName()); } /** * 添加配额条目 * @param quotaEntry */ private void addQuotaEntry(QuotaEntry quotaEntry){ quotaEntries.add(quotaEntry); quotaEntry.setAccount(this); } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isFrozen() { return frozen; } public void setFrozen(boolean frozen) { this.frozen = frozen; } public boolean isOverdrawn() { return overdrawn; } public void setOverdrawn(boolean overdrawn) { this.overdrawn = overdrawn; } public Long getLimit() { return limit; } public void setLimit(Long limit) { this.limit = limit; } public List<QuotaEntry> getQuotaEntries() { return quotaEntries; } public void setQuotaEntries(List<QuotaEntry> quotaEntries) { this.quotaEntries = quotaEntries; } }
测试类
public class QuotaAccountTest { private QuotaAccount account; private QuotaAccount accountTwo; @Before public void setUp() throws QuotaException, ParseException { account = new QuotaAccount(); account.increaseQuota(34); account.setFrozen(false); account.setLimit(10L); account.setOverdrawn(true); account.setName("小明的账户"); accountTwo = new QuotaAccount(); accountTwo.increaseQuota(34); accountTwo.setFrozen(false); accountTwo.setLimit(10L); accountTwo.setOverdrawn(true); accountTwo.setName("小明的账户2"); } @After public void tearDown(){ account =null; accountTwo = null; } @Test public void caclRemainQuota(){ assertEquals(34, account.caclOddQuota()); } @Test public void caclRemainQuotaAfterDeducting4Quotas() throws QuotaException { account.deduct(4); assertEquals(30,account.caclOddQuota()); } @Test public void caclRemainQuotaAfterDeducting44Quotas() throws QuotaException { account.deduct(44); assertEquals(-10,account.caclOddQuota()); } @Test(expected = QuotaException.class) public void caclRemainQuotaAfterDeductingAndAccountItIsNotOverdrawn() throws QuotaException { account.setOverdrawn(false); account.deduct(44); } @Test public void caclRemainQuotaAfterRestoreQuota() throws QuotaException { List<ConsumeQuotaEntry> consumes =account.deduct(44); assertEquals(-10,account.caclOddQuota()); account.restore(consumes); assertEquals(34,account.caclOddQuota()); } @Test public void caclRemainQuotaAferIncreasingQuotaAndDecutingQuota() throws QuotaException { account.increaseQuota(20); List<ConsumeQuotaEntry> consumes =account.deduct(44); assertEquals(10,account.caclOddQuota()); } @Test public void transferSmallQuotas() throws QuotaException { account.transferTo(accountTwo,12); assertEquals(22,account.caclOddQuota()); assertEquals(46,accountTwo.caclOddQuota()); } @Test public void transferMiddleQuotas() throws QuotaException { account.transferTo(accountTwo,34); assertEquals(0,account.caclOddQuota()); assertEquals(68,accountTwo.caclOddQuota()); } @Test public void transferLargeQuotas() throws QuotaException { account.transferTo(accountTwo,44); assertEquals(-10,account.caclOddQuota()); assertEquals(78,accountTwo.caclOddQuota()); } @Test public void transferLargeLargeQuota() throws QuotaException { account.increaseQuota(30); account.transferTo(accountTwo,44); assertEquals(20,account.caclOddQuota()); assertEquals(78,accountTwo.caclOddQuota()); } @Test public void testRepealEntry() throws QuotaException { ProduceQuotaEntry produce = new ProduceQuotaEntry(); produce.setAmount(34); ConsumeQuotaEntry consume =account.repeal(produce); assertEquals(0, produce.getAmount() + consume.getAmount()); } }
发表评论
-
与第三方系统交互的方案设计
2011-11-23 23:18 1922系统与第三方交互时,一般采用Http(s)+xml或we ... -
利用Specification模式检索缓存数据
2011-09-19 13:17 959随着缓存技术的引入,网站前台的检索速度大大提高,随之而 ... -
发一个在学习Junit3.81源码时的小demo
2011-07-30 23:20 915此代码,是在阅读unit3.81源码时写的,虽然有些粗 ... -
对象转化为Xml
2011-05-29 18:12 957内部系统与外部系统对接时,需要进行数据交换,一般是采 ... -
利用Enum解决多种登陆方式
2010-11-24 21:57 9361、需要解决的问题: a、避免出现坏味道,比如过多的if,el ... -
访问历史 的实现
2010-10-20 12:34 1097最近访问历史记录的实现,废话不多说,上代码。 1、Vi ... -
枚举类在Struts2中的运用
2010-10-10 22:20 1941虽然枚举类已经在 jdk1.5 中已经推出来,但是它的 ... -
商品分类以及统计
2010-09-27 13:31 663在卓越网首页的左边,或者当当网的左边,都有商品分类列 ...
相关推荐
3. **结算管理模块**:处理交易后的积分转移和资金结算,确保交易的公正性和有效性。 4. **市场监控模块**:对交易活动进行实时监控,防止市场操纵,确保市场稳定运行。 5. **信息发布模块**:发布市场信息,如价格...
- **控制措施**:包括但不限于碳排放配额管理、碳排放权交易管理、碳排放审计等。 - **目的**:有效控制和管理碳排放,确保合规性。 ##### 3. 碳资产管理与运营 - **资产管理**:全面管理企业的碳资产,包括评估、...
金蝶K3wise供应链管理系统是针对制造企业和商业流通企业设计的一款全面的供应链管理解决方案。该系统旨在优化和控制企业的采购、销售、库存、委外加工等核心业务流程,确保物流、资金流和信息流的高效协同。 **采购...
- **配额管理系统**: 建立碳排放配额分配管理系统,实现配额分配、调整、注销等全流程管理。 - **市场机制**: 引入市场机制,探索碳排放权拍卖、定价等配额分配方式,提高配额分配效率。 **碳排放权交易流程设计** ...
综上所述,该平台旨在通过一系列关键技术的应用和功能模块的设计,有效支持我国实现碳达峰、碳中和的目标,不仅能够帮助企业更好地管理自身的碳排放,还能为政府决策提供科学依据,促进经济社会绿色低碳转型。
Oracle Incentive Compensation (OIC) 是Oracle CRM中的一个强大模块,它帮助企业轻松地设计和实施奖励方案,从而激励销售团队达到甚至超越其业绩目标。OIC提供了一系列功能,使企业能够在全球范围内高效地管理佣金...
Kubernetes是容器编排的领导者,它提供了完整的集群管理能力,包括安全防护、多租户支持、服务注册与发现、负载均衡、故障恢复、滚动升级和在线扩容、资源调度和配额管理。Kubernetes使得服务的部署和管理变得更加...
标题中的“012碳交易机制下考虑需求响应的综合能源系统优化运行”指的是一个研究或项目,它探讨了在碳交易机制下如何通过需求响应技术优化综合能源系统的运行。这个主题涵盖了几个关键的IT知识领域,特别是电力系统...
企业应通过前期调研,将管理需求分为基本的碳排放核算与履约需求,以及更高级别的碳资产交易增值服务需求,以此指导系统的模块设计。 开放灵活的模块设计是MRV机制成功实施的关键。考虑到MRV制度的不确定性和未来...
门店管理模块则涵盖了门店日常运营的各个方面,如顾客管理、会员管理、促销活动管理等。商家可以通过该模块设定不同门店的库存配额,根据销售情况动态调整。同时,系统还支持远程登录,使得总部可以实时监控各门店的...
根据提供的文件内容,这份名为《U9 采购管理用户手册》的手册主要介绍...通过以上知识点的梳理,我们可以看出手册的设计目的是为了引导用户能够熟练地使用U9系统中的采购管理模块,提高企业的采购效率和成本控制能力。
在电力行业中,通过碳交易,发电企业可以购买或出售其排放配额,从而鼓励节能减排。 描述中提到这是“电气相关代码”,适合电子相关专业的学生用于课程设计或学习。这表明提供的代码是实现上述理论概念的实际编程...
该交易中心定位为省服装采购基地,集批发交易、现代仓储、电子商务、商务服务、产品检测和展示等功能于一体,设有信息管理和增值服务模块,旨在推动服装业的发展。 **项目定位** 通过SWOT分析,项目定位考虑了开发...
容器技术为电商架构提供了资源隔离和配额管理的能力,提高了资源利用率和安全性。 - **资源隔离**:通过clone、setns和unshare等系统调用来实现进程间的资源隔离。 - **配额管理**:利用内核提供的命名空间功能,为...
8. **配额管理**:基于供应商的配额分配物料采购,以优化供应链效率。 9. **采购订单自动生成**:通过运行MRP来生成采购申请或计划订单,并根据配额协议等因素自动分配给供应商。 #### 四、物料状态与移动类型 1....
8. **扩展性与可配置性**:作为Java项目,"elec-market"应具有良好的模块化设计,允许用户根据实际需求调整参数、添加新参与者类型或实施新的市场规则。 通过对"elec-market"的深入学习和实践,不仅可以了解电力...
PyQt是Python的一个模块,它允许开发者创建功能丰富的图形用户界面(GUI)应用程序,其基础是Qt库,由Trolltech公司(现为The Qt Company)开发,广泛应用于跨平台应用设计。 在这款应用中,Python的威力得以显现,...