【问题标题】:Help designing a order manager class帮助设计一个订单管理器类
【发布时间】:2009-12-18 19:49:50
【问题描述】:

所以我有一个订单管理器类,如下所示:

public class OrderManager
{
     private IDBFactory _dbFactory;
     private Order _order;

     public OrderManager(IDBFactory dbFactory)
     {
         _dbFactory = dbFactory;
     }


     public void Calculate()
     {

          _order.SubTotal
          _order.ShippingTotal
          _order.TaxTotal

          _order.GrandTotal


     }
}

现在,这里的重点是要有一个灵活/可测试的设计。 我非常担心能否围绕这个 Calculate 方法编写可靠的单元测试。

注意事项:

     1.  Shipping has to be abstracted out, be loose coupled since the implementation of shipping could vary depending on USPS, UPS, fedex etc.  (they have their own API's).
     2. same goes with calculating tax

我是否应该只创建一个 Tax and Shipping Manager 类,并在构造函数中有一个tax/shipping factory? (我的 OrderManager 究竟是如何设计的)类?

(就我“缺少”的东西而言,我唯一能想到的是 IoC,但我不介意这一点,并且在我看来也不需要那种额外的抽象级别)。

【问题讨论】:

  • 编写良好的代码也很容易测试。将您的功能拆分为细粒度的组件,在该级别进行测试。还要对整个事情进行一致的测试。测试代码不需要看起来 100% 优雅。测试人员围绕实现工作,而不是相反。有时会有妥协,但相信我——在现实世界中赚钱的软件市场(大部分市场)中,测试是第二优先的(NASA 的做法不同)。保持简单,直到需要复杂性为止。
  • 这种问题真正要靠多天的白板讨论才能回答。
  • @Jeff Sternal - 同意 - 给出一些可以在白板上得到的想法 :)
  • mrblah,一个问了数百个问题却从不回答一个的人。 -1 给你。

标签: c# asp.net-mvc oop nunit


【解决方案1】:

好吧,您的方法已经开始使用依赖注入,那么为什么不全力以赴并使用某种 IoC 容器来为您处理呢?

是的,如果你想把它抽象出来,然后为它创建一个单独的类。如果您想真正对剩下的内容进行单元测试,请抽象出一个接口并使用模拟测试。问题是,你越是像这样抽象出来,就越需要做更多的管道工作,你会发现自己越希望自己使用某种 IoC 框架。

您建议使用构造函数注入,这是一种常见的方法。您还会遇到属性注入(无参数构造函数,而是设置属性)。还有一些框架要求您实现某种初始化接口,允许 IoC 框架在方法调用中为您进行初始化。使用你觉得最舒服的任何东西。

【讨论】:

  • 我没有完全掌握 Ioc,可能。老实说,为什么我不使用它!
  • 简而言之,IoC 在这里为您做的就是为您提供某种容器或上下文类,然后可以为您提供已经具有这些的订单管理器类的实例为您设置(注入)的依赖项。您只需要担心您需要一个 OrderManager,其余的由 IoC 容器完成。然后在测试场景中,你可以只创建一个新的 OrderManager(而不是使用容器来创建它),然后注入 mock 对象,以便能够单独测试 OrderManager(即对其进行单元测试)。跨度>
【解决方案2】:

我确实认为 IOC 将有助于实例化正确的具体类,但您仍然需要按照您想要的方式进行设计。我确实认为您需要使用一个接口来抽象运输,您可以使用一个类为每个托运人(USPS、UPS、FEDEx 等)实现该接口,并且可以使用工厂类(ShippingManager)来传递正确的一个或依靠国际奥委会为你做这件事。

public interface IShipper
{
//whatever goes into calculating shipping.....
 decimal CalculateShippingCost(GeoData geo, decimal packageWeight);
}

您也可以将 IShipper 和 ITaxer 具体类注入到 OrderManager 中,然后计算方法调用这些类......并且可以很好地使用 IOC 来处理。

【讨论】:

  • 我想我不完全了解 IOC,因此回避它。
  • 你了解控制反转吗?依赖于其他对象的类,它们被传入而不是在类中创建它们。这使得更改依赖项(例如数据层依赖项)以进行测试变得非常容易。
  • @cshapatl 是的,我明白,这就是我对我的 dbfactory 所做的,使用构造函数注入。
  • IOC 会为您处理注入,在大多数情况下,您至少不必直接在应用程序代码中处理具体的类。 IOC 使用配置或可能的领域特定语言进行注入。
【解决方案3】:

只是一个想法:

您的 Calculate() 方法不带参数、不返回任何内容并作用于私有字段,这不是我的做法。我会把它写成一个静态方法,它接受一些数字、一个 IShippingProvider 和一个 ItaxJurisdiction 并返回一个美元总额。这样,您就有机会使用 memoization 缓存对 UPS 的昂贵呼叫和您的税表。

可能是我对像这样工作的公共方法有偏见。过去他们试图绑定控件、使用代码生成器等让我很伤心。

编辑:至于依赖注入/IOC,我认为没有必要。这就是接口的用途。您不会加载一整套古怪的类,只是加载相同权重/邮政编码组合的一些实现。

如果我是你的老板,我会这么说。

【讨论】:

    【解决方案4】:

    我会将Calculate 方法带入一个类。根据您的情况,OrderCalculator 可能需要了解增值税、货币、折扣……

    只是一个想法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-02
      • 1970-01-01
      • 2016-04-09
      相关资源
      最近更新 更多