这只是一个非常普遍的问题,这不仅仅适用于这个例子。
假设您有一个Online Shop,您想要实现代金券/礼物证书,但要有约束。假设您有一张八折优惠券,但这只适用于最近3周内添加的产品,而不适用于特殊促销活动中的产品。
我认为有两种方法可以解决这个问题:第一种方法是将你的商店编码为“原生”支持所有疯狂类型的代金券。这似乎是一种经典的方式,但这意味着事先要做很多工作,灵活性很小(毕竟,你不能事先知道你需要什么,也许销售部门会在下周一之前拿出一些非常棒的新促销活动,需要新的代金券)。
第二种方式是插件方式:代金券就像插件一样,每个代金券都有自己的代码。您将购物篮传入代金券,然后代金券本身检查每个项目(如果适用),进行必要的更改并返回更改后的购物车。
我只是想知道,案例2的设计模式是什么?它看起来有点像IoC/DI,但又不是真的,因为代金券并没有取代任何现有的功能。它更像是一组具有特殊接口对象(即IVoucher),然后是一个遍历的IVoucher对象队列。对于这些类型的“操纵器”,有没有标准的模式(和最佳实践)?
编辑:感谢您的回答。为了澄清一点,优惠券(或操纵者-如上所述,这不仅是关于在线商店的问题,而且是关于类似情况的问题)是“重”对象,也就是说,它们具有业务逻辑。所以我可以说,代金券仅适用于如果客户在2008年1月1日之前注册,只有当客户在过去的6个月中订购了至少100美元,只适用于类别X中的文章,“堆叠”与其他代金券,除了项目标记为减少等。所以我更关心的是如何保持一个干净的结构,以确保代金券得到所有他们需要检查他们是否适用,并能够操纵购物车,所以我想知道这种情况的标准是什么,这正是访客模式似乎所做的。
发布于 2009-02-27 12:51:59
在这种情况下,您可以结合使用the strategy pattern和the vistor pattern来计算篮子的值。
参观者可以使用不同的策略(在这种情况下是折扣券)访问购物篮中的每一项商品,并使用这些策略来计算购物篮的全部成本。
使用的代金券可以通过某种方式从数据库中检索出来,并很容易地注入到访问者中。
代金券策略可能如下所示:
public interface IVoucher
{
decimal CostOf(CartItem cartItem);
}
默认值如下所示:
public class FullPriceVoucher : IVoucher
{
public decimal CostOf(CartItem cartItem)
{
return cartItem.Cost;
}
}
10%的折扣应该是这样的:
public class TenPercentOffVoucher : IVoucher
{
public decimal CostOf(CartItem cartItem)
{
return cartItem.Cost * 0.9m;
}
}
然后你可以有一个访问者来计算购物车的价值,如下所示:
public class CartValueVisitor
{
private IVoucher voucher;
public CartValueVisitor(IVoucher voucher)
{
this.voucher = voucher;
}
public decimal CostOf(Cart cart)
{
return cart.Items.Sum(item => voucher.CostOf(item));
}
}
您可以像这样使用它:
var cart = GetACart();
var fullPriceCartValueVisitor =
new CartValueVisitor(new FullPriceVoucher());
var tenPercentOffCartValueVisitor =
new CartValueVisitor(new TenPercentOffVoucher());
var fullPrice = fullPriceCartValueVisitor.CostOf(cart);
var tenPercentOffPrice = tenPercentOffCartValueVisitor.CostOf(cart);
这显然只适用于一次一张代金券,但应该会让你对一般结构有一个概念。
发布于 2009-02-27 13:32:27
前面提出的Visitor和Strategy模式的答案对我来说听起来很好,尽管Visitor在典型情况下有点夸张,因为每个购买项目都是同一具体类的对象。Visitor的目的是允许动态分派两种(或更多)对象类型--被访问的对象是一个层次结构的一部分,而访问者是另一个层次结构的一部分。但是,如果只有一种对象类型(实现IVoucher
的类的具体类型)发生变化,那么您所需要的就是常规的单一类型虚拟分派。
实际上,我个人根本不会为任何“模式”而烦恼--您自己的描述正是所需的:创建一个接口、IVoucher
和一堆实现该接口的类。您还需要一个工厂方法,该方法接受凭证代码并返回具有适当具体类型的IVoucher
对象。
当心不可交换的代金券!
您提到将针对购买项目运行IVoucher实现对象的队列,这意味着可以使用多个代金券。在这种情况下,您需要小心 --应用凭证A,然后应用凭证B总是与先应用B,再应用A具有相同的效果吗?不幸的是,许多典型的“特别优惠”似乎没有这个属性(例如,如果代金券A给你10美元的折扣,代金券B给你5%的折扣,订单肯定很重要)。
一种快速而肮脏的方法是为每个凭证分配一个不同的数字“优先级”值,并始终以优先级值的顺序应用凭证。为了减少“奇怪”的代金券组合导致您破产的可能性,将代金券组合限制在代码中指定的某一组允许的组合也可能是一个好主意。(这可以像凭证代码列表一样简单。)
发布于 2009-02-27 12:51:46
也许是Visitor pattern?不同类型的代金券是访问者,他们访问购物篮并操纵它。
我不认为IOC是这里的解决方案。
https://stackoverflow.com/questions/594608
复制相似问题