如何创build完美的OOP应用程序
最近我正在尝试一家公司'x'。 他们给了我一些问题,告诉我只能解决一个问题。
问题就是这样 –
基本销售税适用于所有货物的10%,除书籍,食品和医疗产品免除外。
import税是对所有import货物适用的额外销售税,税率为5%,没有豁免。
当我购买物品时,我会收到一张收据,列出所有物品的名称及其价格(含税),以物品的总成本和销售税金总额结束。
销售税的取整规则是,对于n%的税率,p的货架价格包含销售税额(np / 100四舍五入到最接近的0.05)。
“他们告诉我,他们对你的解决scheme的devise方面很感兴趣,并且想评估我的面向对象的编程技巧 。”
这是他们用自己的话讲的
- 对于解决scheme,我们希望您使用Java,Ruby或C#。
- 我们对您的解决scheme的devise方面感兴趣,并希望评估您的面向对象的编程技巧 。
- 您可以使用外部库或工具来build立或testing目的。 具体而言,您可以使用unit testing库或可用于您所选语言的构build工具(例如,JUnit,Ant,NUnit,NAnt,Test :: Unit,Rake等)
- 或者,您也可以包括您的devise和假设以及您的代码的简要说明。
- 请注意,我们不期望一个基于Web的应用程序或一个全面的用户界面。 相反,我们期待一个简单的,基于控制台的应用程序,并对您的源代码感兴趣。
所以我提供了下面的代码 – 你可以复制粘贴代码并在VS中运行。
class Program { static void Main(string[] args) { try { double totalBill = 0, salesTax = 0; List<Product> productList = getProductList(); foreach (Product prod in productList) { double tax = prod.ComputeSalesTax(); salesTax += tax; totalBill += tax + (prod.Quantity * prod.ProductPrice); Console.WriteLine(string.Format("Item = {0} : Quantity = {1} : Price = {2} : Tax = {3}", prod.ProductName, prod.Quantity, prod.ProductPrice + tax, tax)); } Console.WriteLine("Total Tax : " + salesTax); Console.WriteLine("Total Bill : " + totalBill); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.ReadLine(); } private static List<Product> getProductList() { List<Product> lstProducts = new List<Product>(); //input 1 lstProducts.Add(new Product("Book", 12.49, 1, ProductType.ExemptedProduct, false)); lstProducts.Add(new Product("Music CD", 14.99, 1, ProductType.TaxPaidProduct, false)); lstProducts.Add(new Product("Chocolate Bar", .85, 1, ProductType.ExemptedProduct, false)); //input 2 //lstProducts.Add(new Product("Imported Chocolate", 10, 1, ProductType.ExemptedProduct,true)); //lstProducts.Add(new Product("Imported Perfume", 47.50, 1, ProductType.TaxPaidProduct,true)); //input 3 //lstProducts.Add(new Product("Imported Perfume", 27.99, 1, ProductType.TaxPaidProduct,true)); //lstProducts.Add(new Product("Perfume", 18.99, 1, ProductType.TaxPaidProduct,false)); //lstProducts.Add(new Product("Headache Pills", 9.75, 1, ProductType.ExemptedProduct,false)); //lstProducts.Add(new Product("Imported Chocolate", 11.25, 1, ProductType.ExemptedProduct,true)); return lstProducts; } } public enum ProductType { ExemptedProduct=1, TaxPaidProduct=2, //ImportedProduct=3 } class Product { private ProductType _typeOfProduct = ProductType.TaxPaidProduct; private string _productName = string.Empty; private double _productPrice; private int _quantity; private bool _isImportedProduct = false; public string ProductName { get { return _productName; } } public double ProductPrice { get { return _productPrice; } } public int Quantity { get { return _quantity; } } public Product(string productName, double productPrice,int quantity, ProductType type, bool isImportedProduct) { _productName = productName; _productPrice = productPrice; _quantity = quantity; _typeOfProduct = type; _isImportedProduct = isImportedProduct; } public double ComputeSalesTax() { double tax = 0; if(_isImportedProduct) //charge 5% tax directly tax+=_productPrice*.05; switch (_typeOfProduct) { case ProductType.ExemptedProduct: break; case ProductType.TaxPaidProduct: tax += _productPrice * .10; break; } return Math.Round(tax, 2); //round result before returning } }
您可以取消input并运行不同的input。
我提供了解决scheme,但我被拒绝了。
“他们说,由于代码解决scheme不尽如人意,他们不能把我当成现在的职位。”
请引导我在这里缺less的东西。 这个解决scheme不是一个好的OOAD解决scheme吗?
我怎样才能提高我的OOAD技能。
我的老人也说,完美的OOAD应用程序也将无法实际工作。
谢谢
首先, 好天气不会做双倍的财务计算 。 用十进制进行财务计算; 就是这样。 使用双重解决物理问题,而不是财务问题。
您的计划中的主要devise缺陷是政策错误 。 谁负责计算税款? 你已经把产品负责计算税款,但是当你买一个苹果,一本书或一台洗衣机时,你要买的东西不是告诉你你将要支付多less税它。 政府的政策是负责告诉你的。 你的devise大量违反了OOdevise的基本原则,即对象应该为自己的顾虑负责 ,而不是其他任何人。 洗衣机的关注是洗衣服,而不是收取正确的import税。 如果税法发生变化,您不想更换洗衣机对象 ,您想更改保单对象 。
那么,未来如何解决这些问题呢?
我将通过突出显示问题描述中的每个重要名词开始:
基本销售税适用于所有货物的10%,除书籍 , 食品和医疗产品免除外。 import税是对所有import货物适用的额外销售税 , 税率为5%,没有豁免 。 当我购买物品时,我会收到一张收据 ,列出所有物品的名称及其价格 ( 含税 ),以物品的总成本和销售税金总额结束。 销售税的取整规则是,对于n%的税率,p的货架价格包含销售税金额(np / 100四舍五入到最接近的0.05)。
那么所有这些名词之间的关系是什么呢?
- 基本销售税是一种销售税
- import税是一种销售税
- 销售税的税率是十进制的
- 书是一种物品
- 食物是一种物品
- 医疗产品是一种项目
- 物品可能是import货物
- 一个项目有一个名字是一个string
- 一个物品的货架价格是十进制的。 (注:一件物品是否真的有价格?两台相同的洗衣机可能在不同的商店有不同的价格出售,或者在不同的时间在不同的商店出售不同的价格。一个更好的devise可能是说一个定价政策它的价格。)
- 销售税豁免政策描述了销售税不适用于某个项目的条件。
- 收据包含物品清单,价格和税金。
- 收据总数
- 收据有总税
… 等等。 一旦你把所有名词之间的所有关系都解决出来,那么你就可以开始devise一个类层次结构。 有一个抽象的基类Item。 书从它inheritance。 有一个抽象类SalesTax; BasicSalesTax从它inheritance。 等等。
如果公司告诉像NUnit这样的库,JUnit或Test :: Unit比TDD真的重要。 在你的代码示例中根本没有testing。
我会尝试展示以下实践知识:
- unit testing(例如NUnit)
- 嘲弄(如RhinoMocks)
- 持久性(如NHibernate)
- IoC容器(例如NSpring)
- devise模式
- 固体原则
我想推荐www.dimecasts.net作为免费的,高质量的屏幕录像,其中涵盖了上述所有主题的令人印象深刻的来源。
这是非常主观的,但这里有几点我会做你的代码:
-
在我看来,你混合了
Product
和ShoppingCartItem
。Product
应该有产品名称,税务状况等,但不是数量。 数量不是产品的属性 – 对于购买特定产品的公司的每个客户而言,数量是不同的。 -
ShoppingCartItem
应该有一个Product
和数量。 这样客户可以自由地购买更多或更less的相同的产品。 用你目前的设置是不可能的。 -
计算最终税也不应该是
Product
一部分 – 它应该是ShoppingCart
一部分,因为最终的税收计算可能涉及到了解购物车中的所有产品。
首先,这是一个很好的面试问题。 这是一个很好的衡量许多技能。
有许多事情你需要理解,以提供一个很好的答案( 没有完美的答案),无论是高层次和低层次。 这里有一对夫妇:
- 领域build模 – >你如何创build一个好的解决scheme模型? 你创build什么对象? 他们将如何解决这些要求? 寻找名词是一个好的开始,但是如何决定你select的实体是否好? 你还需要其他什么实体? 你需要什么样的领域知识来解决它?
- 分离关注点,松耦合,高凝聚力 – >如何区分devise中具有不同关注点或变化率的部分,以及如何将它们联系起来? 你如何保持你的devise灵活和最新?
- unit testing,重构,TDD – >您提出解决scheme的过程是什么? 你写testing,使用模拟对象,重构,迭代?
- 清洁代码,语言习语 – >您是否使用编程语言的function来帮助您? 你写可理解的代码? 你的抽象层次是否有意义? 代码的可维护性如何?
- 工具 :你使用源代码pipe理? 构build工具? 集成开发环境?
从这里开始,您可以进行许多有趣的讨论,涉及devise原则(如SOLID原则),devise模式,分析模式,领域build模,技术select,未来演化path(例如,如果添加数据库或丰富的UI层,什么需要改变?),权衡,非function需求(性能,可维护性,安全性…),验收testing等等。
我不会评论你应该如何改变你的解决scheme,只是你应该更多地关注这些概念。
但是,我可以告诉你我是如何(部分地)解决这个问题的 ,就像一个例子(在Java中)。 查看Program
课程 ,看看它们是如何组合在一起打印此收据的:
------------------这是你的命令------------------ (001)领域驱动devise----- $ 69.99 (001)日益增长的面向对象软件----- $ 49.99 (001)House MD Season 1 ----- $ 29.99 (001)House MD第七季----- 34.50美元 (IMD)越来越多的面向对象软件----- $ 2.50 (BST)House MD Season 1 ----- $ 3.00 (BST)House MD Season 7 ----- $ 3.45 (IMD)House MD Season 7 ----- $ 1.73 小计----- $ 184.47 税务总额----- $ 10.68 总计----- $ 195.15 ----------------感谢您select我们----------------
你一定要看看这些书:-)
正如一个警告:我的解决scheme还很不完善,我只是专注于快乐的道路情景,以便有一个良好的基础。
除了你正在使用一个名为product的类,你没有certificate你知道什么是inheritance,你没有创build多个从Productinheritance的类,没有多态。 这个问题可以通过使用多个OOP概念来解决(甚至只是为了表明你知道它们)。 这是一个面试问题,所以你想显示你知道多less。
我现在不会变成抑郁症。 你没有在这里展示他们并不意味着你不知道他们或不能学习他们。
你只需要多一点面试或面试的经验。
祝你好运!
开始使用面向对象编程进行编程的人员不会有很大的问题来理解它的含义,因为它与现实生活中的一样 。 如果你有比OO更好的编程技能,可能会更难以理解。
首先,closures你的屏幕,或退出你最喜欢的IDE。 拿一张纸和一支铅笔 ,列出实体 , 关系 , 人员 , 机器 , stream程 , 东西等等。
其次,尝试获得不同的基本实体。 你会明白,有些人可以分享属性或能力 ,你必须把它放在抽象的对象 。 你应该开始画出一个很好的程序模式。
接下来,你必须把function(方法,function,子程序,你想要的)称为:例如,一个产品对象不应该能够计算销售税 。 销售引擎对象应该。
不要在所有的大词汇( 界面 , 属性 , 多态性 , 遗产等)和devise模式中遇到麻烦,甚至不要试图制作漂亮的代码或其他东西…只要想想简单的对象和它与现实生活中的 相互作用 。
之后,尝试阅读一些严肃的文学作品。 我认为维基百科和维基教科书是一个非常好的开始,然后只是阅读有关GoF和devise模式和UML的东西。
一个完美的面向对象的实现是完全有争议的。 从我在你的问题中看到的,你可以基于它们执行的angular色来模块化代码,以计算最终的价格,比如Product,Tax,ProductDB等等。
-
Product
可以是一个抽象类,像Books,Food这样的派生类可以inheritance它。 税收适用性可以由派生types决定。 产品将根据派生类来判断税收是否适用。 -
TaxCriteria
可以是一个枚举,这可以在购买时指定(import,销售税适用性)。 -
Tax
类将根据TaxCriteria
计算税额。 -
拥有XXBBCCbuild议的ShoppingCartItem可以封装产品和税收实例,这是将产品详细信息与数量,总价格和税收等分开的好方法。
祝你好运。
从严格的OOA / Dangular度来看,我所看到的一个主要问题是,大多数类属性在属性名称中具有类的多余名称。 例如产品价格,types的产品 。 在这种情况下,无论你使用这个类,你都会有过于冗长的代码,比如product.productName。 从您的属性中删除多余的类名前缀/后缀。
另外,在问题中我没有看到有关购买和创build收据的任何类。
以下是产品,税收等OO模式的一个很好的例子。请注意使用接口,这在OOdevise中是必不可less的。
http://www.dreamincode.net/forums/topic/185426-design-patterns-strategy/
关于devise规则的一个非常好的起点是SOLID原则。
例如,Open Closed原则规定,如果你想添加新的function,你不必添加代码到现有的类,而是添加新的类。
对于您的示例应用程序,这意味着添加新的销售税将需要添加新的类。 对于规则例外的不同产品也是如此。
舍入规则显然是分开的 – 单一责任原则规定每个class级都有单一的责任。
我认为,自己编写代码会比仅仅编写一个好的解决scheme并将其粘贴在这里带来更多的好处。
一个简单的algorithm来编写完美的devise程序将是:
- 写一些解决问题的代码
- 检查代码是否符合SOLID原则
- 如果有规则违规比goto 1。