有没有实施折扣模型的已知设计模式?
通过折扣模型,我的意思是:
如果客户购买产品X,产品Y和产品Z,则可获得10%或$ 100的折扣。
如果客户购买100个产品X,他将获得15%的折扣或$ 500
如果客户去年带来的收入超过$ 100K,则可获得20%的固定折扣
如果客户购买了2个单位的产品X,则可以免费获得1个单位的产品X(或产品Y)。
...
是否可以使用一种通用模式来处理所有上述情况?我正在考虑一些模型,但无法遇到通用模型。
有没有实施折扣模型的已知设计模式?
通过折扣模型,我的意思是:
如果客户购买产品X,产品Y和产品Z,则可获得10%或$ 100的折扣。
如果客户购买100个产品X,他将获得15%的折扣或$ 500
如果客户去年带来的收入超过$ 100K,则可获得20%的固定折扣
如果客户购买了2个单位的产品X,则可以免费获得1个单位的产品X(或产品Y)。
...
是否可以使用一种通用模式来处理所有上述情况?我正在考虑一些模型,但无法遇到通用模型。
Answers:
如果问题是您需要应用多个折扣,则在给定的情况下,您可能需要考虑“ 责任链”模式。
简而言之,您可以将要处理的信息传递到第一个处理器,然后在返回结果之前决定是否从那里将其传递给其他处理器。
这样,您可以更改处理器的结构和顺序,而无需更改调用代码。
策略,装饰者和状态模式对我来说是潜在的起点。状态对于2或3可能特别有用,因为2取决于订单的状态,而3取决于一段时间内的客户的状态。策略和装饰器在其他产品中脱颖而出,因为您可以使用策略来实现多个订单价格计算算法,装饰器可以为订单添加新的折扣。
但是,请记住,设计模式只是模型。可能没有适用的单个模式,而是一个模式系统。还可以考虑对描述的模型进行修改,以使其更适合您的解决方案。拥有一个好的设计总比强迫一个模式不一定要有用,因为仅仅为了能够说出您有一个模式,这是更好的选择。
好吧,我将折扣模型设计为“ Precondition”和“ Discount”对,其中“ Precondition”是带有方法的类
bool IsFulfilled(Customer c);
或/和
bool IsFulfilled(Customer c, Order o);
折扣有一种方法void ApplyTo(Customer c)
。这使您能够将任何类型的前提条件与任何类型的折扣组合在一起(我认为这是“过渡模式”的一种形式)。
如果您有固定数量的前提条件,则可以通过构建特定的子类型(策略模式)来解决问题。但是,当您的前提条件非常复杂时,使用AND,OR和NOT这样的逻辑语句,则可以更好地为条件实现某种规则解释器。规则可以是用简单的“特定于域的语言”编写的纯文本字符串。
对于“折扣”类也是如此,您可以为不同类型的折扣提供一些子类型,也可以采用一种通用方法,其中折扣规则以文本形式给出,并由某些解释程序进行评估。
可能需要一个IDiscount接口,因为所有不同的折扣都是同一件事,我们将在概念上将它们作为通用折扣来处理。
“此客户的订单”类可能需要折扣集合。清单?哈希?链表?不在乎。折扣适用于购买,不适用于客户!
将Discount实例的构建与客户,购物车,历史记录等分开。这会发生很大变化-正如@jfrankcarr指出的那样。
每种折扣的类别可能不同,因为每种折扣的算法和参数变化很大且无法预测。
我看到很多事件处理,因为折扣计算会响应购物车的更改,反之亦然。
设计模式应用
strategy pattern
。IDiscount是用于实现不同折扣算法的接口。我看到一个factory
。abstract factory pattern
在分析的这一点上,当然不是成熟的,而是单个类。合理地,必须在一个地方有足够的上下文来确定要应用哪些折扣,然后再创建折扣。一堂课 我认为,如果后来由于市场部的热闹派对而导致折扣折扣规则突然爆发,那么我认为,在这个基础工厂类别中,仍然必须合并任何其他折扣建设逻辑。
我可以看到Chain of Responsibility
。这不是该factory
想法相互排斥的。每个折扣都将呼叫下一个人,而不是迭代折扣集合。在这种情况下,“客户订单”类不包含折扣集合。
我认为,责任链中的“嗯……”因素是,每项折扣都有一个参考。含义是顺序很重要。事实并非如此。同样,CoR体现的概念是一个对象无法处理该请求,因此将其“传递给下一个更高的权限”。我们的模型是不同的。唯一的要求是计算。每个折扣都可以做到这一点。输出或效果可能为空,但会计算所有折扣。我本能地倾向于更高的真实度。
假设条件
什么变化,什么保持不变?
折扣大不相同。组成每个规则的参数数量和种类不同。
随着购物车的更改,合格折扣的参数也会更改。
可用折扣数量变化
该客户的折扣符合其购物车变更时的变更资格。
购物历史不会因此次购买而改变
总成本随采购额和折扣的变化而动态变化。
首次应用后,折扣的输出可能会发生变化,例如,购买数量发生变化。
从逻辑上讲,折扣模型可以是任何模型,因此您不能假设可以事先对所有情况进行编程。回答您问题的任何人也不能完全确定您的实际需求。但是,假设您获得了现实世界中常见的折扣...
一个很大的问题是,是否将对折扣进行编程,或者是否希望用户输入折扣。如上所述,您永远不能对它们进行编程,但是通常的目标是像在一般情况下那样,尝试使其更多的数据输入,而不是全部编程。即使使用程序员来创建所有折扣,这在一定程度上也适用。
马丁·福勒(Martin Fowler)在“分析模式:可重用对象模型”中提到了“个体实例方法”,这是如何为会计系统实施“过帐规则”的一部分,但该规则与您的规则相当相似。我会提供更多细节,但这是受版权保护的作品,
对于用户界面,您要么需要提出非常简单的用例,要么构建一个解释器和查询构建器。可能两者兼而有之,一种用于简单案例,另一种用于高级案例。如果您确实编写了解释器,则使用Interpreter模式可能是一个相当不错的情况,因为与解析器生成器相比,它的编码相对简单,解析时间的缩短可能并不重要。(如果您喜欢使用解析器生成器,请不要让我阻止您)。
但是,不要尝试使用解释器来做所有事情-在某些时候,您只是在使用自己的简陋语言进行编程,因此您不妨使用一种真正的语言。如果您的解释语言支持功能(它可能应该支持调用它们-定义它们是可疑的),则可以用真实语言进行编码。不要沿着这条路走下去。
无论您做什么,最终都会有人希望折扣基于他们是否在促销后的30个工作日内购买-工作日仅在商店的邮政编码或客户的邮政编码所定义的区域中没有假日的情况下才算邮政编码。因此,不要尝试预先设计完美的系统-假设您有时需要编写代码来获得新的折扣并相应地进行设计。
有什么问题要问是否有一个有用的模式吗?需要哪种类型的模式-结构或行为模式?
理想情况下,如果我要为此编写软件,则只需一个算法即可。计算总折扣的简单函数如下:
cart.calculateDiscount(productVector);
您只需要这些!
需要澄清的是:我知道会有很多规则-这种表示的最基本的应该是规则库的形式(数据属性集和相对于它的折扣),并且上面的函数会对其进行迭代以对其进行计算。如果添加或删除了规则,则不应最终更改代码-只需更改规则库即可。
仅当我们需要不同的对象需要访问彼此的API或进行通信以将任务放置到位时,才需要使用模式。
PS:考虑一下-当防火墙处理数据包并通过或拒绝数据包(或对其进行修改)时,它将使用哪种设计模式?答案是上述任何一个!