【问题标题】:how to design a custom product builder如何设计定制产品构建器
【发布时间】:2014-10-24 13:35:30
【问题描述】:

我正在开发一个应用程序,用于对汽车等产品进行估算。 So, when a car make an model is selected, I need to present various options to the user (options may be in different groups like Wheels, Seating Upholstery, Trunk Accessories)

根据组的不同,客户可以在该组中选择一个或多个选项;如果选择了某个选项 - 其他一些选项可能会被禁用;并非所有选项都适用于每个制作模型 那么,对于不同的组,需要定义几条规则来指示哪些组合是允许的,哪些是不允许的?

我应该如何为此设计数据库?在开发此应用程序时,我是否可以利用一种模式?

【问题讨论】:

  • 根据您的问题的复杂性,您可能会发现领域驱动设计有助于将代码拆分为更小且更易于维护的模块,同时提供更深入的洞察力

标签: asp.net database-design e-commerce


【解决方案1】:

我用下面的结构解决了一个类似的要求,用你上面的术语重写:

  1. 零件
  2. 汽车

附注如下:

  1. 部件本身是独立的,每个部件都有一个部件号。
  2. 汽车模板本身就是独立的。
  3. 可以将零件添加到一个选项组中,并且多个选项组属于一辆车。
  4. 没有汽车就不能存在选项组。
  5. 一个组可以依赖另一个组
  6. 我需要防止循环引用

在编写类代码(测试驱动开发)之前,我通过编写测试用例开始使用我的模型,这给了我代码(在 C# 中):

var dieselEngine = new Sku("diesel 2_litre,",1000);
var petrolEngine2 = new Sku("petrol_2_litre",800);
var petrolEngine25 = new Sku("petrol_25_litre",900);

var petrolTurbo = new Sku("petrol_turbo",2000);
var dieselTurbo = new Sku("diesel_turbo",2000);

var car = new Car("myCar");

car.AddGroup("Engines");
car.AddSkuToGroup("Engines", diselEngine);
car.AddSkuToGroup("Engines", petrolEngine2);
car.AddSkuToGroup("Engines", petrolEngine25);

car.AddGroup("Turbos");
car.AddSkuToGroup("Turbos", petrolTurbo);
car.AddSkuToGroup("Turbos", dieselTurbo);

car.SetRequirement(diselEngine, dieselTurbo);
car.SetRequirement(petrolTurbo, petrolEngine2);
car.SetRequirement(petrolTurbo, petrolEngine25);

我在组而不是 Sku 上添加依赖项选项,因为一个部件可能存在于多辆汽车中,但对于每辆特定汽车可能具有不同的依赖关系。

我必须通过根汽车对象放置所有内容,这将检查并执行我的所有业务规则(例如检查和防止循环引用)。

如果通过汽车对象进行的所有访问都感觉很笨重,您总是可以让car.AddGroup 函数返回一个组,以使代码更易于阅读:

var engines = car.AddGroup("Engines");
engines.AddSkuToGroup(diselEngine);
engines.AddSkuToGroup(petrolEngine2);
engines.AddSkuToGroup(petrolEngine25);

但不要忘记,业务规则只能由汽车执行,因为汽车具有所有组件的可见性。所以我们总是通过根链接起来:

class ConfigurableProduct
{
    List<Group> groups = new List<Group>();
    Group NewGroup(string name)
    {
        var group = new Group(this, name);
        this.groups.Add(group);
        return group;
    }

    bool ContainsSku(string skuId)
    {
        foreach (var group in this.Groups)
        {
            if (group.ContainsSku(skuId))
                return true;
        }
        return false;
    }
}

class Group
{
    Group(ConfigurableProduct parent, string name)
    {
        this.parent = parent;
        this.name = name;
    }

    string name;
    List<string> skuIds = new List<string>();

    ConfigurableProduct parent;

    void AddSkuToGroup(string skuId)
    {
        // enforce invariants via parent, call functions as reuqired
        if (this.parent.containsSku(skuId))
            throw new Exception("SKU already exists in this configurable template, cannot exist twice");
        // do other things, like check circular references etc, all via this.parent

    }

    bool ContainsSku(string toFind)
    {
        foreach (var skuId in this.skuIds)
        {
            if (skuId == toFind)
                return true;
        }
        return false;
    }
}

对于实际的数据库存储,我最后会担心持久性,它可以是文本文件、MSSQL 数据库、MySQL 数据库、MongoDB,有很多选择。

我发现专注于我想如何在我的应用程序中使用代码总是有用的,而不是需要如何使用数据库的细节,因为可以通过返回类的存储库接口抽象存储(a普通的旧 POCO 类,但在这种情况下,我们已经开始充实业务逻辑以防止无效状态)。

对于前端,您可能希望通过 JSON 将这一切下推至诸如 angular 或 knockout 之类的东西,它们可以动态呈现可用选项,并根据组之间的依赖关系显示或隐藏不同的元素。

前端工作示例

我不确定您使用的是什么前端绑定(或者如果您只使用剃须刀,在这种情况下,您需要在服务器上存储状态并刷新每个选择),但我提供了一个使用 Knockoutjs 的示例这里:http://jsfiddle.net/g18c/5jt9bwsv/1/ 具有工作依赖项和动态 javascript 对象构建器。

  1. 按组循环提供的 JSON 产品
  2. 创建根据目标依赖关系变化的计算字段
  3. 通过敲除绑定到视图

然后可以简单地将选定的 SKU 传递给服务器,任何业务规则也可以在前端 javascript 中实现。

当然,从客户端发送到服务器的任何数据都需要通过在服务器上构建产品图并检查提供的 SKU 是否有效来进行验证(即,您不希望允许 Diesel Turbo被选为汽油发动机)。

【讨论】:

  • 非常感谢@g18c 的详细回答。我将对此进行详细审查并回来将其标记为答案:)
  • @PratikKothari 希望这对您有所帮助,如果这回答了您的问题,将不胜感激将其标记为已回答,如果您仍有问题,请告诉我,并很乐意回答。您也可以随时打开赏金以吸引更多关注您的问题!
  • 由于项目的一些要求发生了变化,我仍在处理一些细节。您的回答非常彻底,感谢您抽出宝贵时间提供 jsfiddle 链接。我已将此标记为答案。再次感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多