如何创建完美的OOP应用程序

sun*_*der 99 c# oop

最近我在尝试一家公司'x'.他们给我发了一些问题并告诉我只解决一个问题.

问题是这样的 -

所有商品的基本销售税适用率为10%,但免税的书籍,食品和医疗产品除外.
进口税是适用于所有进口商品的额外销售税,税率为5%,不含豁免.

当我购买物品时,我收到一张收据,其中列出了所有物品的名称及其价格(含税),最后是物品的总成本,以及所支付的销售税总额.
销售税的舍入规则是对于n%的税率,p的货架价格包含(np/100四舍五入到最接近的0.05)销售税金额.

"他们告诉我,他们对您的解决方案的设计方面感兴趣,并希望评估我的面向对象编程技巧."

这是他们用自己的话说的

  • 对于解决方案,我们希望您使用Java,Ruby或C#.
  • 我们对您的解决方案的DESIGN ASPECT感兴趣,并希望评估您的面向对象编程技巧.
  • 您可以使用外部库或工具进行构建或测试.具体来说,您可以使用单元测试库或可用于您所选语言的构建工具(例如,JUnit,Ant,NUnit,NAnt,Test :: Unit,Rake等)
  • 或者,您也可以在设计和假设以及代码中包含简要说明.
  • 请注意,我们不期望基于Web的应用程序或全面的UI.相反,我们期待一个简单的,基于控制台的应用程序,并对您的源代码感兴趣.

所以我提供了以下代码 - 你可以复制粘贴代码并在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
     }
 }
Run Code Online (Sandbox Code Playgroud)

您可以取消注册输入并运行不同的输入.

我提供了解决方案,但我被拒绝了.

"他们说,他们无法考虑我当前的空缺职位,因为代码解决方案并不令人满意."

请指导我这里缺少什么.这个解决方案不是一个好的OOAD解决方案.
我怎样才能提高我的OOAD技能.
我的老年人也说完美的OOAD应用程序也不会起作用.

谢谢

Eri*_*ert 246

好天堂首先不要进行双倍的财务计算.用十进制进行财务计算; 这就是它的用途.使用double来解决物理问题,而不是财务问题.

您的计划中的主要设计缺陷是政策错误.谁负责计算税收?你已经让产品负责计算税收,但是当你购买苹果或书籍或洗衣机时,你要购买的东西并不负责告诉你要支付多少税款.它. 政府政策有责任告诉你.您的设计大量违反了基本的OO设计原则,即对象应该对自己的问题负责,而不是其他任何人的问题.洗衣机的问题是洗衣服,而不是收取正确的进口税.如果税法改变,您不想更改洗衣机对象,您想要更改策略对象.

那么,未来如何处理这些问题呢?

我首先要强调问题描述中的每个重要名词:

所有商品的基本销售税适用率为 10%,但免税的书籍,食品医疗产品除外.进口税是适用于所有进口商品的额外销售税,税率为5%,不含豁免.当我购买物品时,我收到一张收据,其中列出了所有物品名称及其价格(含税),最后是物品的总成本,以及所支付的销售税总额.销售税的舍入规则是对于n%的税率,p 的货架价格包含(np/100四舍五入到最接近的0.05)销售税金额.

现在,所有这些名词之间的关系是什么?

  • 基本销售税是一种销售税
  • 进口税是一种销售税
  • 销售税的税率为十进制
  • 书籍是一种物品
  • 食物是一种物品
  • 医疗产品是一种物品
  • 物品可以是进口货物
  • Item具有Name是String
  • 物品的货架价格为十进制.(注意:一件物品真的有价格吗?两个相同的洗衣机可能会在不同的商店以不同的价格出售,或者在不同的时间在同一家商店出售.更好的设计可能是说定价政策将物品与物品相关联它的价格.)
  • 销售税免税政策描述了销售税不适用于物品的条件.
  • 收据包含物品清单,价格和税金.
  • 收据总计
  • 收据的总税额

... 等等.一旦你掌握了所有名词之间的所有关系,你就可以开始设计一个类层次结构了.有一个抽象基类Item.本书继承自它.有一个抽象类SalesTax; BasicSalesTax继承自它.等等.

  • +1你突出了一个非凡的练习,即检查所述问题中的每个名词,然后列举彼此之间的关系.很好的主意. (31认同)
  • @sunder:这个答案绰绰有余.现在你有责任培养你的技能,或许以此为例.请注意,您的示例是现实生活示例的定义.你没有通过现实生活中的访谈,因为这个真实的代码需要你没有提供的真实设计. (27认同)
  • 你需要的不仅仅是刚提供的东西吗?听起来你需要了解更多关于如何实现继承以及什么是多态的知识. (12认同)
  • @Narayan:`double`非常适合在正确答案的0.00000001%范围内绰绰有余的情况.如果你想弄清楚一块砖在半秒后下降的速度,那就做双打算.当您在双打中进行*financial*arithemtic时,你最终会得到税后价格为43.79999999999999美元的答案,即使它非常接近正确的答案,这看起来很傻. (9认同)
  • @Jordão:在十进制中,添加0.10十次确实给出1.00.但是增加1.0/333.0三百三十三次并不一定能得到十进制或双数.在十进制中,分母中具有10的幂的分数被精确表示; 在双打中,它是具有2的幂的分数.其他任何东西都是近似的. (3认同)
  • "双打"没有给出精确的结果,复合计算后更是如此; 和会计师不喜欢丢失便士...这将打印`False`:`Console.WriteLine(Enumerable.Range(0,10).Aggregate(0.00,(acc,i)=> acc + 0.10)== 1.00 )`,即添加0.10 10次不会给你1.00. (2认同)

Rad*_*dek 38

如果公司告诉我们有关像NUnit这样的库,那么JUnit或者Test :: Unit很可能是TDD真正重要的.在您的代码示例中根本没有测试.

我会尝试展示以下方面的实用知识:

  • 单元测试(例如NUnit)
  • 嘲弄(例如RhinoMocks)
  • 持久性(例如NHibernate)
  • IoC容器(例如NSpring)
  • 设计模式
  • SOLID原则

我想建议www.dimecasts.net作为令人印象深刻的免费,优质网络广播的来源,涵盖所有上述主题.


xxb*_*bcc 19

这是非常主观的,但以下是我对您的代码所做的几点:

  • 在我看来,你混合ProductShoppingCartItem.Product应该有产品名称,税务状态等,但不是数量.数量不是产品的属性 - 对于购买该特定产品的公司的每个客户而言,数量都是不同的.

  • ShoppingCartItem应该有一个Product和数量.这样,客户可以自由购买更多或更少的同一产品.使用您当前的设置是不可能的.

  • 计算最终税也不应该是Product- 它应该是一些事情的一部分,ShoppingCart因为最终的税收计算可能涉及了解购物车中的所有产品.


Jor*_*dão 14

首先,这是一个非常好的面试问题.它是衡量许多技能的好方法.

你需要了解很多东西才能提供一个好的答案(没有完美的答案),无论是高级还是低级.这是一对夫妇:

  • 域建模 - >如何创建解决方案的良好模型?你创建了什么对象?他们将如何解决这些要求?寻找名词是一个好的开始,但你如何决定你的实体选择是否良好?你需要什么其他实体?您需要哪些领域知识才能解决它?
  • 关注点分离,耦合松散,内聚力高 - >如何将设计中具有不同关注点或变化率的部分分开,以及如何将它们联系起来?您如何保持您的设计灵活和最新?
  • 单元测试,重构,TDD - >您提出解决方案的过程是什么?你写测试,使用模拟对象,重构,迭代?
  • 清洁代码,语言习语 - >您是否使用编程语言的功能来帮助您?你写的是可以理解的代码吗?你的抽象层次是否有意义?代码的可维护性如何?
  • 工具:您使用源代码管理吗?构建工具?集成开发环境?

从那里,您可以进行许多有趣的讨论,包括设计原则(如SOLID原则),设计模式,分析模式,领域建模,技术选择,未来发展路径(例如,如果我添加数据库或富UI层,什么需要改变?),权衡,非功能性要求(性能,可维护性,安全性......),验收测试等......

我不会评论你应该如何改变你的解决方案,只是你应该更多地关注这些概念.

但是,我可以向您展示我(部分)如何解决这个问题,就像一个例子(在Java中).在Program课堂上查看如何将所有内容组合在一起打印此收据:

------------------ THIS IS YOUR ORDER ------------------
(001)                Domain Driven Design -----   $69.99
(001)    Growing Object Oriented Software -----   $49.99
(001)                 House M.D. Season 1 -----   $29.99
(001)                 House M.D. Season 7 -----   $34.50
(IMD)    Growing Object Oriented Software -----    $2.50
(BST)                 House M.D. Season 1 -----    $3.00
(BST)                 House M.D. Season 7 -----    $3.45
(IMD)                 House M.D. Season 7 -----    $1.73
                                SUB-TOTAL -----  $184.47
                                TAX TOTAL -----   $10.68
                                    TOTAL -----  $195.15
---------------- THANKS FOR CHOOSING US ----------------

你一定要看看那些书:-)

正如一个警告:我的解决方案仍然非常不完整,我只关注快乐路径场景,以便有一个良好的基础来构建.


And*_*i G 12

除了你使用的是一个名为product的类,你还没有证明你知道什么是继承,你没有创建多个继承自Product的类,没有多态.可以使用多个OOP概念解决问题(甚至只是为了表明你了解它们).这是一个面试问题,所以你想表明你知道多少.

然而,我现在不会变成抑郁症.你没有在这里展示它们的事实并不意味着你不了解它们或者无法学习它们.

您只需要在OOP或面试时获得更多经验.

祝好运!


smo*_*nff 10

已经开始用OOP学习编程的人在理解它的含义方面没有很大的问题,因为它就像在现实生活中一样.如果你有其他编程技能而不是面向对象的技能,那么理解它可能会更加困难.

首先,关闭屏幕,或退出您喜欢的IDE.拿一张和一支铅笔,列出实体,关系,人员,机器,流程,东西等等,这些可以在最终的程序中遇到.

其次,尝试获得不同的基本实体.您将了解有些人可以共享 属性能力,您必须将它放在抽象对象中.你应该开始绘制一个很好的程序模式.

接下来,您必须设置fonctionnalities(方法,函数,子例程,根据需要调用它):例如,产品对象不应该能够计算销售税.一个销售引擎对象应该.

不要在第一时间对所有大字(接口,属性,多态,遗产等)和设计模式感到麻烦,甚至不要尝试制作漂亮的代码或其他任何东西......只要想到简单的对象和它与现实生活中的相互作用.

之后,尝试阅读一些关于此的严肃简洁的文章.我认为维基百科维基教科书是一个非常好的开始,然后只是阅读有关GoF和设计模式UML的东西.

  • +1为"首先,关闭你的屏幕".我认为思维的力量经常被误认为是计算的力量. (3认同)