2013-02-20 138 views
1

我被赋予了一项任务,那就是编写一个简单的程序来打印一份杂货店顾客的收据。知道基本销售税适用于所有商品的10%税率,但免除的书籍,食品和医疗产品除外。 进口关税是对所有进口货物适用的附加销售税,税率为5%,无豁免。面向对象的设计

示例输入:1美元10美元的书籍,1美元的进口巧克力条,5美元等等。

我想使程序尽可能以对象为导向。所以我的层次是这样的:

顶层是抽象类Item(name,price),然后我将有类SaleTaxItem(需要支付10%税的项目)和NonSaleTax项目类从Item扩展。问题是我应该在上面的每个类中创建一个名为isImported的布尔变量,以便我知道何时收取5%的费用?或者我应该为导入的项目创建一个新类?

这个设计对于这个任务非常重要,所以我想让它完美。谢谢!

+1

为什么不只是写一个方法'getTax ()'哪些返​​回10%的SaleTaxItem和10%+ 5%的项目是否可以进口(可能重写?)?我不认为布尔是一个很好的可扩展选择:想象一下,我们引入了新的税收:我们是否需要引入新的布尔值?我们是否需要在int中进行编码? – 2013-02-20 06:45:44

+0

雅我有getTax()其中我目前使用布尔值来决定是否收取5%的进口税。我在Item类中实现了is_import布尔值。如果我不使用布尔值,那么我应该使用什么? – 2013-02-20 07:03:44

回答

2

关于何时使用继承以及何时不使用,存在着巨大的讨论。在这种情况下,我会而不是使用继承来建模您的项目。

为什么?因为在现实生活中,这些税收和责任规则在时间,空间(例如你所在的国家)以及你正在运行的公司类型中经常发生变化。如果每当地方政府和联邦政府更改其规定时都必须更改班级层级,那么您注定会失败 - 更新会更改您已拥有实例的班级 - 您的项目。另一个考虑:如果您使用类(有效地)将销售标记为具有税收和/或责任,那么您将最终得到一些没有标记接口的项目,并且一些项目具有多个 - 即使用多重继承。你需要四个班级。添加一些额外的规则,并且你有一个班级爆炸(考虑税种/职责数量的因子)。

另一种实现方式是拥有一个属性,该属性是项目所具有的税收和关税的集合。所以,你有两个班,:

  • 项目

    • 列表:税收
    • 字符串:命名
    • 双:百分之

税收有许多全局实例 - SalesTax和ImportDuty。然后,一个项目在列表中具有零个,一个或两个Tax实例(并且该列表还暗示订单纳税被应用)。

这最后一种方法也是更好的适应未来的税制改革,包括增加新税种

编辑一夜之间我有一个改进的建议:

enter image description here

有两种'wings'to the diagram:

  1. AbstractItem层次结构,处理Item和i税收
  2. TaxOrDuty层次结构和TaxAssessor中的算法。

AbstractItem在Item上使用decorator pattern,将Item包装在税层中 - 每个层由TaxedItem建模。最外层是包裹在所有适用税款中的物品,并且使用装饰者模式,除了虚高价格外,其外观和行为都与物品相同。该AbstractItem有几个有用的方法:

  • 用getPrice():返回全价的项目
  • getAllTaxes()的:通过在一个空的列表,以及递归方法在装饰收集TaxOrDuty实例。这对于能够对装饰物品的税收进行分项很重要
  • getUntaxedItem():通过装饰物递归直到它找到它返回的物品。这可以轻松从装饰物品中检索原始物品。

在税收方面,有一类TaxOrDuty模拟税收的抽象行为。在这个天真的实现中,每个税都有一个统一的税率,但是您可以轻松地将该行为推到FlatRateTax类中。其方法是:

  • 的getRate():返回税收或关税摘要方法。这是在子类上实现的
  • computeTax()方法获取一个项目并根据getRate()计算税金
  • isApplicable()是一个抽象方法,如果税项适用于Item,则返回true。这在SalesTax上执行(总是返回true)和ImportDuty(返回Item.isImported)

TaxAssessor是负责协调适用税收分配的类。它包含所有TaxOrDuty实例的列表(在本例中只是SalesTax的一个实例和ImportDuty之一)。它的方法applyTaxes(Item)遍历这个集合调用isApplicable()。对于返回true任何TaxOrDuty,该TaxAssessor包裹项目在TaxedItem(当然它引用TaxOrDuty)的新实例:

AbstractItem applyTaxes(Item item) { 
    taxed = item; 
    for (TaxOrDuty td : taxes) { 
      if (td.isApplicable(item)) { 
       taxed = new TaxedItem(td, taxed); 
    return taxed; 

所以你的整体答案是这样的:

Item item = new Item("Book", 10.0, false); // New $10 book, not imported 
AbstractItem withTaxes = taxAssessor.applyTaxes(item); 
double taxedPrice = withTaxes.getPrice(); 
List<TaxOrDuty> applicableTaxes = withTaxes.getAllTaxes(new List<TaxOrDuty>()); 

这种模式的主要优点是:

  • 新税种是可插拔
  • 纳税评估和计算算法是税收的一部分,而不是在项目,所以非常复杂的税收可以在自己的阶级独立且准确地模拟
  • 责任是明显的(对我来说),并明确划定
+0

无论如何,我可以确定哪个项目是应税的?我的意思是,例如,我只有一个类Item,当我创建一个新的Item并向构造函数提供一个名称“chocolate”时,构造函数会认识到巧克力是食物并且对这个价格征税?! – 2013-02-20 21:40:12

+1

@CharlieVictor:我已经用一个很好的模型来回答这个问题,我已经更新了我的答案。 – 2013-02-21 00:57:18