如何灵活存储一个产品的多个价格?
我想建立一家商店,其中的产品有一个小向导,通过它可以确定价格。 在这种情况下,我谈论的是印刷产品。
因此,举个(小)例子,当您来到商店想要打印名片时,您需要决定是要打印黑白还是彩色,如果您想选择厚纸还是薄纸,如果您想要打印 100、200、500 或 1000 件等。
毕竟会有一个价格,比如说:黑白,厚纸,200张=> 40,-$
实际上你还有更多的选择可供选择。 正如您所想象的,有很多价格,但没有公式。
所以我的问题是:我该如何处理价格?
我的第一个想法:装饰器模式。
但当我转念一想,这并不是一个好主意。 正如我所说,没有真正的公式,我还必须生成向导(如果您想打印贺卡,向导可能会有所不同)。 另外,我希望能够通过管理界面更改价格或添加产品或添加新的“决定”,例如“您想要光面纸吗?” 到产品或删除产品(并且仍然保持价格不变)。
所以现在我正在考虑为每个产品使用一棵树,我可以在其中添加级别(新决策)、度假村级别等。
另一个想法是通过决策构建某种关键对象,并在价格表中查找价格。 有点像字典,我在其中添加决策,毕竟我从中生成一个键来在价格表中查找价格。
因此,在制作原型之前,我想知道我是否只是盲目的,没有看到明显的解决方案,或者也许还有另一种我不知道的更优雅的方法?
I want to build a shop in which the products have a little wizard through which the price then is determined. In this case I'm talking about printing products.
So for (a little) example when you come to the shop and want to print a business card, you get to decide if you want to print black and white or in color, if you want to choose thick paper or thin, if you want to print 100, 200, 500 or 1000 pieces and so on.
After all there will be a price for let's say: black and white, thick paper, 200 piece => 40,-$
In real you have many more choices to choose from. So as you can think there are many many prices, for which there is no formula.
So my question is: How can I handle the prices?
My first idea: Decorator Pattern.
But when I thought about it, it's not a very good idea. As I told there is no real formula, also I have to generate the wizard (which may be different if you want to print greeting cards). Also I want to be able to change the price trough a admin interface or add a product or add a new "decision" like "do you want glossy paper?" to a product or remove one (and still keep the prices intact).
So now I'm thinking about using a tree for each product in which I can add a level (a new decision), resort levels and so on.
Another Idea is to Build some Kind of Key-Objects through the decisions and look the price up in a Price table. A bit like a Dictionary in which I add the decisions and after all I generate a key out of it to look up the price in a price table.
So before prototyping I was wondering if I'm just blind and I don't see the obvious solution or maybe there is another way which is more elegant I don't know about?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
嗯,我的想法相当复杂,但你的愿望也很复杂。
您所描述的向导的问题是,在他们做出所有选择后,他们可能想回到#2并更改一件事以查看它如何改变价格 - 但您构建向导的方式可能会影响以后是否可以做出选择,并导致您必须为每个产品自定义一组相当复杂的代码 - 而不是将所有内容很好地存储在数据库中,以便代码可以完成所需的所有操作,并且任何产品更改都会发生到数据库中,而不是代码更改。
首先,您需要了解您有定价逻辑,理想情况下这将与演示分开。 换句话说,您应该能够向一个客户提供分步向导,并向另一个客户提供带有复选框选项和字段的单个页面,并让他们构建具有相同限制的相同内容。
尽量避免设计数据库,这样你就无法做到其中之一。 换句话说,如果您执行“选择您自己的冒险”风格的向导,您就会限制未来的选择(以及客户的灵活性)。 原因是,如果我执行 10 个步骤,然后更改步骤 2,我必须再执行 8 个步骤 - 如果你保证我不会重复我已经做出的选择,这可能没问题,但如果我只是改变纸张颜色我不想再做同样的 8 个选择。 如果您确实走这条路,请确保保留大量状态,以便他们之前所做的选择下次显示为默认选择。
我会考虑向数据库添加一层抽象。 我希望看到一个矩阵,其中每个选项以及显示兼容性的产品和流程,而不是指定用户可以选择的树路径。
例如,我有三种纸张类型、3 种颜色和 3 种工艺:
纸张
颜色
处理
然后我会为每场比赛定价:
空白表示不能混合的项目。
值得注意的条目:
这只是一个示例一个简单的化身 - 每个价格实际上都是到另一个表的链接,如果数量在一定范围内(即 100 个可能比 10 个便宜),则该表给出每个价格。 它还可以确定费用是每张纸、每次操作还是每个订单 - 并且这可能会叠加(因此每张纸的装订费用可能为 0.001,以考虑切刀的磨损,并且 0.50每本装订书的单价,然后总共 5 美元的装订操作安装费用)
考虑到您拥有的东西数量巨大,您可以做其他事情,这很快就会变得相当复杂。
但是,一旦输入数据,您就可以在指定成本并将其呈现给用户方面获得无限的灵活性。 例如,您可能会发现,值得将每种不同型号的打印机放在自己的列中(而不是仅仅将它们全部称为打印机),并根据纸张类型、颜色和打印操作为客户找到最低的打印价格。
您还可以在矩阵中填写人工(时间),以便可以在与价格估算相同的位置给出时间估算。
无论您是执行向导,还是立即显示页面上的所有内容,此后端都将支持它。 看看戴尔在笔记本电脑配置方面的做法——你不能用其他东西来获得某些东西。 因此,如果您在页面上显示所有选项,那么当它们从普通纸张更改为卡片纸时,您可以提醒他们,“您还选择了折叠,这与卡片纸不兼容。您确定要这样做吗?”改变?”
但首先也是最重要的 - 首先编写用例并设计整个系统。 如果你现在就开始编写如此复杂的代码,你现在就会做出决定,以后很难撤消,但稍后你会发现你必须做出重大改变,或者在功能上做出妥协。
当然,选择自己的冒险风格更容易设计和开发,唯一的问题是如果你添加一个新的流程或论文,你可能必须更新200棵树,并添加50棵新树。 商店中的每次变更都需要部署新的数据库(可能还包括软件),这会延迟资本支出的回报。 如果你一开始就让它非常灵活,那么现在会更难,以后会更容易/更快。
此外,您不会将客户限制在树选项上 - 如果他们确实想在一侧通过 4 色印刷机进行打印,在另一侧通过廉价复印机进行打印,如果工艺和材料兼容,他们可以探索该选项。 过去 20 个产品/流程,您无法真正完全填写树。
最后,它可以让您非常非常精细地控制成本。 如果您的业务流程在细粒度水平上跟踪机器使用情况和成本(维护等),您可能会低于竞争对手的出价,因为您知道您的机器每页成本恰好 0.00234,而他们则陷入困境一般的猜测。 如果您开始使用该系统进行跟踪并让员工跟踪问题、维护等,您可能会发现非常奇怪的相关性,例如红色卡片库存在折叠机上的成本更高,因为它比蓝色卡片更频繁地堵塞(无论出于何种原因)。 你可以调整你的定价(在这个系统中,调整到第n级),与纸张制造商交谈,停止提供该选项,或者采取一些其他策略来挤压系统。 如果您的某些机器需要熟练的操作员,您可以将员工及其工资率添加到矩阵中,并开始安排工作,以便他们更高效地工作。
更新
好吧,我已经简化了上面的内容,但让我们先假设简单的情况。
上表中我没有提及每个价格代表什么。 除装订外,所有内容的费用均按页计算。 绑定成本是每个绑定项目的成本。
因此,在您的示例中,您选择浅色纸、红色、打印。 每张红纸为 0.05 美元(昂贵的纸张!),每张印刷品为 0.001 美元(廉价印刷),因此每张印刷纸的成本为 0.051 美元。 如果您要复印 300 份,则总费用为 15.30 美元。
由于装订是按每个装订项目列出的,因此您可以将装订添加到上述订单中,并且您可能将 50 页装订在一起,总共 6 个装订项目,300 页。 我们已经知道前面所有物品的成本,因此 6 个绑定物品(每件 0.50 美元)的额外成本为 3.00 美元,新的总计为 18.30 美元。
除了我上面指定的简化之外,您还需要做一些事情:
在矩阵中,我将许多单元格留空。 在某些情况下,这是因为进程/对象不兼容(例如,无法绑定折叠项目),但在其他情况下,没有冲突,但它不会花费任何费用。 因此,您的红色/常规与常规/红色的示例 - 因为我们将价格加在一起,所以替代组合不需要任何成本。
让我们看看我是否可以更清楚地说明这一点...
选择浅色纸,红色,印刷,装订(300 页,6 个装订项目)遍历表格并找到该集合中的所有价格:
您搜索表中的所有元素(红色/浅色和浅色/红色),然后将价格分别乘以数量,然后求和。 所有这些选择的交集以绿色显示。 (浅色纸/浅色纸着色混乱 - 也应该是绿色)
我删除了打印/打印组合,因为它不适用于这种方法(我希望简化事情,但它实际上使事情变得更困难)如果你如果想要指定双面打印,您将需要表中的另一个项目(例如,反向打印),并且您可以同时选择打印和反向打印。 交替有两个项目,“单面打印”和“双面打印”。
请记住,虽然我在每个单元格中列出了每个价格,但实际情况是每个单元格实际上描述了一些情况:
#1 中的引用引用了另一个表其中包含价格和第三个维度。 例如,组合“light/bound”的单元格将引用具有以下三个属性的表格:
这些将根据页数和装订项目的数量进行求和,然后将每个工作的成本添加到上面。
更加复杂! 哇!
这可能适合您的需求,但是如果您的流程仅在某些更复杂的情况下不兼容怎么办?
现在我们可以涵盖一个进程或对象与另一个进程或对象冲突的一般情况。 然而,我们无法处理更复杂的事情。
假设轻质纸可以打印,也可以折叠,但不能既打印又折叠。 我们不能对打印/折叠施加限制,因为其他纸张可以打印和折叠。
您可以做一些事情:
向量很好,但对于这个应用程序来说可能有点过分了。 它基本上是第一个项目,但没有定义您可以拥有多少个维度 - 您拥有与对象一样多的维度,因此可以表示任何可能的组合。
附加的抽象层是两者之间的折衷。 理想情况下,您不会遇到比两个项目更复杂的冲突,但是当您遇到冲突时,您将定义一个代表组合的新对象。 因此,在这种情况下,您可能有一个新的对象/过程,它是打印和折叠的组合,并且它在轻质纸张的列上有约束。
您只能针对约束执行此操作,在这种情况下,它不会修改您的定价算法(即,定价仍然来自单个进程和对象的添加。)
或者,您可以使用选择最大组合的算法 - 因此在数据库中搜索“浅色”、“红色”、“打印”、“折叠”时,您首先要在数据库中搜索组合,这将返回“浅色”、“红色”、“打印折叠”的最大组合,然后正常定价。
最后,您可以在数据库中搜索单个项目和组合项目,如果存在冲突(组合项目和单个项目的双重定价),那么您可以选择:
-Adam
Well, the idea I'm having is rather complex, but your desire is complex as well.
The problem with the wizard you are describing is that after they've made all their choices, they may want to go back to #2 and change one thing to see how it changes the price - but the way you're building your wizard it may affect whether later choices can be made at all, and result in a rather complex set of code you have to customize for each product - instead of storing everything nicely in a database such that the code can do everything needed, and any product changes go into the database, not code changes.
First, you need to understand that you have pricing logic, and ideally this will be separate from presentation. In other words, you should be able to present a step by step wizard to one customer, and a single page with checkbox options and fields to another and have them build the same thing with the same restrictions.
Try to avoid designing the database so you can't do one or the other. In other words, you restrict future options (and customer flexibility) if you do a "choose your own adventure" style wizard. The reason is that if I go through 10 steps, then change step 2, I have to go through 8 more steps - this may be fine if you guarantee that I'm not duplicating choices I've already made, but if I'm only changing paper color I don't want to make the same 8 choices again. If you do go this route, make sure you keep a lot of state around so that the choices they've made previously show up as the default next time through.
I would consider adding one more level of abstraction to the database. Rather than specify the path through a tree that the user can select, I'd like to see a matrix with each option and product and process showing compatibility.
For instance, I have three paper types, 3 colors, and 3 processes:
Paper
Color
Process
Then I'd have pricing for each match:
Empty spaces denote items that can't be mixed.
Notable entries:
This is just a sample of a simple incarnation - each price would actually be a link to another table that gives the price per each if the quantity is within a certain range (ie, 100 might be cheaper than 10). It would also hold whether the charge is per piece of paper, per operation, or per order - and this might stack (so you might have a binding charge of 0.001 per piece of paper to account for wear and tear on the cutters, and 0.50 per bound book for the piece price, then $5 setup charge for the binding operation altogether)
This will quickly become pretty complex given the shear number of things you have that you can other things to.
But once the data is entered it will give you unlimited flexibility in specifying costs and presenting them to the user. You may find, for instance, that it's worthwhile putting each different model of printing machine in its own column (rather than just calling them all printers) and finding the lowest printing price for the customer based on the paper type, color, and printing operations.
You can also fill out the matrix with labor (time) so that you can give time estimates in the same place as price estimates.
Whether you do a wizard, or show everything on the page at once, this backend will support it. Look at what Dell does for laptop configurations - you cant' get certain things with other things. So if you display all the options on a page, then when they change from regular paper to card stock you can alert them with, "You've also chosen folding, which is incompatible with card stock. Are you sure you wish to make this change?"
But first and foremost - write up use cases and design the system as a whole first. If you jump in now and start coding something this complex, you're going to make decisions now that will be very hard to undo later, but you'll find later you have to either make major changes, or compromise on a feature.
Of course, the choose your own adventure style is much easier to design and develop, the only problem is that if you add a new process or paper, you may have to update 200 trees, and add 50 new trees. Every change in the shop requires a new database (and possibly software) rollout, which delays payback on capital expenses. If you make it very flexible up front, it's harder now, and easier/faster later.
Furthermore, you don't limit your customers to the tree options - if they really want to print via 4 color press on one side, and cheap copier on the other they can explore that option if the processes and materials are compatible. Past 20 products/processes, you can't really fully fill out the tree.
Lasty, it gives you very, very fine control over cost. If your business process tracks machine usage and cost (maintenance, etc) at a fine grained level, you can underbid your competitor because you know that your machine costs exactly 0.00234 per page, whereas they're stuck with the generic guess. If you start tracking using this system and make employees track problems, maintenance, etc, you may find very odd correlations such as red card stock costs you more at the folding machine because it jams more frequently than the blue (for whatever reason). You can either adjust your pricing (to the nth degree, in this system), talk to the paper manufacturer, stop offering that option, or a number of other tactics to squeeze the system. If some of your machines require skilled operators you can add employees to the matrix with their pay rate, and start scheduling jobs so they're working more efficiently and effectively.
Update
Well, I've simplified the above, but let's assume the simple case first.
I didn't mention in the above table what each price represented. The cost for everything is per page, except binding. The cost for binding was per bound item.
So in your example you choose Light paper, red, print. Each piece of red paper is $0.05 (expensive paper!) and each print is $0.001 (cheap printing) so the cost per piece of printed paper is $0.051. If you are making 300 copies, then the total charge is $15.30.
Since binding is listed per bound item, then you might add binding to the above order, and you might be binding 50 pages together, for a total of 6 bound items, 300 pages. We already know the cost of everythign preceding, so the additional cost of 6 bound items (at $0.50 per item) is $3.00, for a new total of $18.30.
There's a few things you're going to have to do beyond the simplification I've specified above though:
In the matrix I've left many cells empty. In some cases that's because the processes/objects are incompatible (can't bind folded items, for instance) but in other cases there's no conflict, but it doesn't cost anything. So your example of red/regular vs regular/red - since we're adding prices together the alternate combination costs nothing.
Let's see if I can make this more clear...
The selection light paper, red, printed, bound (300 pages, 6 bound items) go through the table and finds all the prices that fall inside that set:
You search for all elements in the table (both red/light and light/red) and then take the prices and multiply by the quantity individually, then sum them. The intersection of all these selections is shown in green. (Messed up on the light paper/light paper coloring - should be green too)
I removed the printing/printing combination because it won't work with this method (I was hoping to simplify things, but it actually makes things harder) If you want to specify double sided printing you'll need another item in the table (Print Reverse, for instance) and you'd select both print and print reverse. Alternately have two items, "print single side" and "print double side".
Keep in mind that while I've listed each price in each cell, the reality is that each cell actually describes a few circumstances:
The reference in #1 refers to another table which contains the prices and a third dimension. For instance, the cell at combination "light/bound" would reference a table that has the following three attributes:
These would be summed according to the number of pages and bound items, and then the per job cost is added on top.
More complexity! Woo!
This may work for your needs, but what if you have processes that are only incompatible in certain more complex situations?
Right now we can cover the general case of one process or object conflicting with another. We cannot, however, handle anything more complex.
Suppose that the light paper can be printed, and it can be folded, but it can't be both printed AND folded. We can't put a constraint on Print/Fold because other papers can be both printed and folded.
There are a few things you can do:
Vectors are nice, but might be overkill for this application. It is basically the first item, but without defining how many dimensions you can have - you have as many dimensions as you have objects, so any possible combination can be represented.
The additional layer of abstraction is a compromise between the two. Ideally you won't have very many conflicts that are more complex than two items, but when you do, you define a new object that represents a combination. So in this case you might have a new object/process that is the combination of printing and folding, and it has a constraint at the column with light paper.
You can do this only for constraints, in which case it doesn't modify your pricing algorithm (ie, pricing still comes from the addition of individual processes and objects.)
Alternately, you can use an algorithm that selects the greatest combination - so instead of searching the database for Light, Red, Print, Fold you'd first search the database for combinations, which would return the greatest combination of Light, Red, PrintFold, and then price it normally.
Lastly, you might search the database for both individual and combinatory items, and where there's a conflict (double pricing of combination and individual items) then you either select:
-Adam