【问题标题】:Best way to data model the same Java Class with different functionalities对具有不同功能的相同 Java 类进行数据建模的最佳方法
【发布时间】:2017-11-11 11:37:08
【问题描述】:

案例:

通常产品对象具有以下属性:

  1. 姓名
  2. 价格

但在促销周期间,虽然大部分产品仍然只有名称和价格作为属性,但部分选定的产品会获得附加属性:

  • 颜色

但是在促销周之后,这些之前促销的产品将失去颜色属性,再次成为标准产品。

当前实施:

我有 2 个课程 -> Product 和 ProductPromotion

public class Product {

    private String name;
    private BigDecimal price;
    private ProductPromotion promotion;

    public Product(String name, BigDecimal price) {
        this.name = name;
        this.price = price;
    }

    public void setProductPromotion(ProductPromotion promotion) {
        this.promotion = promotion;
    }
}


public class ProductPromotion {

    private Color color;

    public ProductPromotion (Color color) {
        this.color = color;
    }
}

如您所见,Product 单方面引用了 ProductPromotion。默认产品对象对其 ProductPromotion 有一个空引用,而带有促销的产品,我只是这样做:myproduct.setProductPromotion(new ProductPromotion(Color.RED));

每当我决定我的产品的促销活动结束时,我都会这样做: myproduct.setProductPromotion(null);

我的问题:

我真的不喜欢对每个非促销产品都有一个对 ProductPromotion 的空引用,因为这种建模并不是很漂亮。我的意思是,如果占位符不包含任何内容(至少对于非促销产品),为什么我们需要保留一个占位符。所以我想请有经验的程序员更好地实现这个功能。

进一步思考:

根据您的意见和想法,我能够提出一种新方法,我非常欢迎您对此提出想法:

我会将 ProductPromotion 类拆分为默认版本和提升版本:

public class ProductPromotion {
    private boolean promotionDisabled;

    public ProductPromotion() {
        setPromotionDisabled(true);
    }

    public boolean isPromotionDisabled () {
        return promotionDisabled;
    }

    public boolean setPromotionDisabled (boolean value) {
        promotionDisabled = value;
    }
}

public class ProductPromotionEnabled extends ProductPromotion {
    private Color color;

    public ProductPromotion (Color color) {
        super(false);
        this.color = color;
    }

    public Color getColor () {
        return color;
    }

    public void setColor(Color color) {
        this.color = color;
    }
}

所以我会创建一个类型为 ProductPromotion 的 defaultPromotionObject,它引用了任何非提升对象。而促销对象将指向 ProductPromotionEnabled 类型的promotionEnabledObject。您对此有何看法?

【问题讨论】:

  • 只需添加color 属性,无论您是否立即不需要它。您可以说颜色为 null 或值为零表示完全没有颜色。
  • @C0dekid 您好,我刚刚添加了我当前的代码实现。
  • @Enzokie 是的,我就是这么做的。但是有没有更好的解决方案不需要有一个恒定的颜色占位符,因为颜色空引用并不合乎逻辑(如果产品没有颜色,为什么我仍然需要明确告诉大家它没有有颜色)?
  • Since color null reference are not really logical 我不同意,null一个标志,表示产品没有颜色。完全没有颜色属性表示产品直到永远都不会有颜色。毕竟这是 Java。
  • 是的,它是 Java。我认为可能有更好的方法来模拟 Product 和 ProductPromotion 之间的关系,其中我不需要对任何默认 Product 对象使用空引用。

标签: java oop data-modeling


【解决方案1】:

类定义实体的属性和行为。 当我们在类中放入私有的“ProductPromotion 促销”属性时,这意味着所有产品都应该有促销,并且为了表明特定产品没有促销,我们在其中放置一个空值。

不应该这样。 实现此目的的更好方法是从 Product 类中删除“私有 ProductPromotion 促销”属性,并将 ProductPromotion 类重命名为PromotedProduct。 PromotedProduct 应该从 Product 继承,因此它是具有促销的特定类型的产品。

这样我们就有了两个类。 Product 和PromotedProduct(特定类型的产品),然后我们可以使用多态对产品列表进行操作。

代码:

public class Product {

    private String name;
    private BigDecimal price;

    public Product(String name, BigDecimal price) {
        this.name = name;
        this.price = price;
    }

}

public class PromotedProduct extends Product {

    private Color color;

    public PromotedProduct(String name, BigDecimal price ,Color color) {
        super(name ,price);
        this.color = color;
    }
}

Product product[3];
product[0] = new Product("keyboard",100);
product[1] = new PromotedProduct("stick", 80 ,Color.RED);

等等。

【讨论】:

  • 您好,是的,我也在考虑这一步。但是问题来了,假设我有一个产品:零可乐。在夏季,该产品会以某种颜色进行促销,但在夏季之后,它将恢复到原来的形式,不附加任何颜色。您将如何为这种特定场景建模?
  • 每次提升和恢复对象时,我们都必须创建一个新的对象副本。我认为这样做的更好方法是创建新的构造函数和 getter,以便可以执行以下代码。产品[0] =新的PromotedProduct(产品[0],Color.RED);产品[0] = 产品[0].getProduct();
  • 是的,你说得有道理。使产品对象不可变是尽可能安全的。您能否详细说明我将如何根据数据库实现这一目标?例如。我们有一个产品可乐,它当前存储在 db_table_products 中,pk=1。现在它被提升了,所以 pk=1 的旧条目将被删除,而自动递增 pk=10 的新条目将被添加到 db_table?那么每次产品更改促销时->删除旧条目,创建新条目?
  • 在数据库方面创建两张表,product(ID, name, price)和promotedProduct(ID, Color)。 promotedProduct 的主键是引用 product.ID 的外键。这样,产品表中就会添加一个产品。当它被提升时,在promotedProduct 表中添加它的ID 和颜色,当它被恢复时,只需从promotedProduct 中删除它的条目。
  • 我完全了解现在的情况。非常感谢您抽出宝贵时间在这件事上帮助我。我将您的回答标记为最有助于找到合适的解决方案。
【解决方案2】:

使用类Optional。这消除了null 值,实际上您似乎想要这种关系。

private Optional<ProductPromotion> promotion = Optional.empty();

promotion.ifPresent(promo -> promo...);

另一种方法是将产品映射到促销活动。

【讨论】:

  • 您的代码肯定有助于规避空指针异常。我宁愿寻找一种方法来模拟 Product 和 ProductPromotion 之间的关系,以便任何产品都可以轻松地切换正在促销或不促销。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
  • 2016-02-20
  • 1970-01-01
  • 1970-01-01
  • 2012-09-22
  • 2020-01-30
  • 1970-01-01
相关资源
最近更新 更多