帮助设计订单管理器类
所以我有一个订单管理器类,如下所示:
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
我是否应该创建一个税收和运输管理器类,并在构造函数中拥有一个税收/运输工厂? (我到底是如何设计我的 OrderManager 的)类?
(就我“缺少的”而言,我唯一能想到的是 IoC,但我不介意这一点,并且在我看来不需要额外的抽象级别)。
So I have an order manager class that looks like:
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
}
}
Now, the point here is to have a flexible/testible design.
I am very concerned about being able to write solid unit tests around this Calculate method.
Considerations:
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
Should I just create a Tax and Shipping Manager class, and have a tax/shipping factory in the constructor? (exactly how I have designed my OrderManager) class?
(the only thing that I can think of, in terms of what I am "missing", is IoC, but I don't mind that and don't need that extra level of abstraction in my view).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
好吧,您已经在方法中转向依赖注入,那么为什么不全力以赴并使用某种 IoC 容器来为您处理这个问题呢?
是的,如果您希望将其抽象化,请为其创建一个单独的类。如果您想真正对剩下的内容进行单元测试,请抽象出接口并使用模拟测试。问题是,你这样抽象得越多,需要做的工作就越多,你就会发现自己越希望使用某种类型的 IoC 框架。
您建议构造函数注入,这是一种常见的方法。您还会遇到属性注入(无参数构造函数,而是设置属性)。还有一些框架要求您实现某种初始化接口,以允许 IoC 框架在方法调用中为您进行初始化。使用您觉得最舒服的任何东西。
Well, you are already moving towards dependency injection in your approach, so why not go the whole hog and use some sort of IoC container to handle this for you?
Yes, if you want it abstrated out, then create a separate class for it. If you want to truly unit test what is left, abstract out an interface and use mock testing. The problem is, the more you abstract out like this, the more plumbing together there is to do and the more you will find yourself wishing you were using an IoC framework of some kind.
You are suggesting constructor injection, which is a common approach. You also come across property injection (parameterless constructor, set properties instead). And there are also frameworks that ask you to implement an initialization interface of some kind that allows the IoC framework to do the initialization for you in a method call. Use whatever you feel most comfortable with.
我确实认为 IOC 将有助于实例化正确的具体类,但您仍然需要按照您想要的方式进行设计。我确实认为您需要使用一个接口来抽象运输,您可以使用每个托运人(USPS、UPS、FEDEx 等)的类来实现该接口,并且可以使用工厂类(ShippingManager)来传递正确的一个或取决于国际奥委会为你做这件事。
您还可以将 IShipper 和 ITaxer 具体类注入到 OrderManager 中,然后计算方法只需调用这些类......并且可以很好地使用 IOC 来处理该问题。
I do think an IOC would help with the plumbing of instantiating the correct concrete classes but you still need to get your design the way you want it. I do think you need to abstract away the shipping with an interface that you can implement with a class for each of your shippers (USPS, UPS, FEDEx, etc) and could use a Factory class (ShippingManager) to pass the correct one out or depend on the IOC to do that for you.
You could also just inject an IShipper and ITaxer concrete classes into your OrderManager and you calculate method just calls into those classes....and can use an IOC nicely to handle that.
只是一个想法:
你的Calculate()方法不带参数,不返回任何内容并且作用于私有字段,这不是我会做的。我会将其编写为静态方法,该方法接受一些数字、IShippingProvider 和 ITaxJurisdiction,并返回美元总额。这样,您就有机会使用记忆功能缓存对 UPS 的昂贵呼叫和税表。
可能是我对这样的公共方法存在偏见。他们过去试图绑定到控件、使用代码生成器等让我很恼火。
编辑:至于依赖注入/IOC,我不认为有必要。这就是接口的用途。您不会加载一整套古怪的类,而只是加载相同权重/邮政编码组合的一些实现。
如果我是你的老板我也会这么说。
Just a thought:
Your Calculate() method taking no parameters, returning nothing and acting on private fields is not how I would do it. I would write it as a static method that takes in some numbers, an IShippingProvider and an ITaxJurisdiction and returns a dollar total. That way you have an opportunity to cache the expensive calls to UPS and your tax tables using memoization.
Could be that I'm prejudiced against public methods that work like that. They have burned me in the past trying to bind to controls, use code generators, etc.
EDIT: as for dependency injection/IOC, I don't see the need. This is what interfaces were made for. You're not going to be loading up a whole array of wacky classes, just some implementations of the same weight/zipcode combo.
That's what I would say if I were your boss.
我会将计算方法放入一个类中。根据您的情况,OrderCalculator 可能需要了解增值税、货币、折扣……
只是一个想法。
I would take the Calculate method out into a class. Depending on your circumstances OrderCalculator might need to be aware of VAT, Currency, Discounts, ...
Just a thought.