所以我有一个看起来像的订单管理器类:
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类,并在构造函数中设置税/运输工厂吗? (确切地说我是如何设计我的OrderManager)类?
(就我所“缺失”而言,我唯一可以想到的是IoC,但我不介意,并且在我的视图中不需要额外的抽象级别。)
答案 0 :(得分:1)
嗯,你已经开始在你的方法中采用依赖注入了,那么为什么不去整个生猪并使用某种IoC容器为你处理这个?
是的,如果你想要它被抽象出来,那么为它创建一个单独的类。如果你想真正单元测试剩下的东西,抽象出一个接口并使用模拟测试。问题是,你这样抽象得越多,就越需要管道连接,你会发现自己希望使用某种类型的IoC框架越多。
您建议构造函数注入,这是一种常见的方法。您还会遇到属性注入(无参数构造函数,而不是设置属性)。还有一些框架要求您实现某种初始化接口,允许IoC框架在方法调用中为您进行初始化。使用你觉得最舒服的任何东西。
答案 1 :(得分:1)
我认为IOC会帮助实现正确的具体类的管道,但您仍然需要按照自己的方式设计。我确实认为你需要通过一个接口来抽象出货,你可以用每个托运人(USPS,UPS,FEDEx等)的类来实现,并且可以使用Factory类(ShippingManager)传递正确的一个或者依靠国际奥委会为你做到这一点。
public interface IShipper
{
//whatever goes into calculating shipping.....
decimal CalculateShippingCost(GeoData geo, decimal packageWeight);
}
您也可以将一个IShipper和ITaxer具体类注入到OrderManager中,并计算方法只调用这些类....并且可以很好地使用IOC来处理它。
答案 2 :(得分:1)
只是一个想法:
你的Calculate()方法没有参数,什么都不返回,并且在私有字段上行动不是我怎么做的。我会把它写成一个静态方法,它接受一些数字,一个IShippingProvider和一个ITaxJurisdiction并返回一个总计美元。这样,您就有机会使用memoization将昂贵的呼叫缓存到UPS和税表。
可能是因为我对那种有效的公共方法有偏见。他们过去曾试图绑定到控件,使用代码生成器等等。
编辑:至于依赖注入/ IOC,我认为没有必要。这就是为什么建立接口。你不会加载一大堆古怪的类,只是一些相同的重量/邮政编码组合的实现。如果我是你的老板,那就是我想说的。
答案 3 :(得分:0)
我会把Calculate方法带到一个类中。根据您的具体情况,OrderCalculator可能需要了解增值税,货币,折扣......
只是一个想法。