在 OOP 中处理成员依赖关系的最佳方法是什么?

时间:2021-02-20 02:08:27

标签: c++ oop

我有一个 Position 类,它代表这样的股票头寸:

class Position {
private:
    double price_;
    double amount_;
    double value_;

public:
    void SetPrice(double price) {
        price_ = price;
    }

    void SetAmount(double amount) {
        amount_ = amount;
    }

    double GetValue() {
        return value_;
    }
...
}

3 个成员应满足等式:price * amount = value。但是每个成员都可以从 setter 更改,保持等式是一个问题。

我有 4 种不同的处理方法:

  1. 不要存储 value_,并在每次需要时在 getter 中填充值:
class Position {
private:
    double price_;
    double amount_;
    // double value_;
...

public:
    double GetValue() {
        return price_ * amount_;
    }
}

优点:

  • 非常清楚

缺点:

  • 真正的问题不仅仅是这么简单。例如,我应该如何处理类 total value 中的多个位置和 Portfolio 位置?
  • getter 可能很耗时。
  1. 在依赖项发生变化时计算 value_
class Position {
private:
    double price_;
    double amount_;
    double value_;
...

public:
    void SetPrice(double price) {
        price_ = price;
        value_ = price_ * amount_;
    }

    void SetAmount(double amount) {
        amount_ = amount;
        value_ = price_ * amount_;
    }

    double GetValue() {
        return value_;
    }
}

优点:

  • getter 很简单

缺点:

  • 但是所有的setters都会很耗时,
  • 并且代码非常复杂,选项 1)
  1. 在设置其他成员时使用 std::optional 或类似的技术,清除 value_
class Position {
private:
    std::optional<double> price_;
    std::optional<double> amount_;
    std::optional<double> value_;
...

public:
    void SetPrice(double price) {
        price_ = price;
        value_.reset();
    }

    void SetAmount(double amount) {
        amount_ = amount;
        value_.reset();
    }

    double GetValue() {
        if (!value_) {
            value_ = price_.value() * amount_.value();
        }
        return value_;
    }
}

优点:

  • setter 比选项 2) 清楚得多

缺点:

  • setters 中还有其他逻辑
  1. 像技术一样使用 make 应用程序,将 timestamp 附加到这些成员上。
class TimestampData {
private:
    double value_
    std::time_t time_;

public:
    TimestampData& operator=(double value) {
        value_ = value;
        time_ = std::time(nullptr);
    }
}


class Position {
private:
    TimestampData price_;
    TimestampData amount_;
    TimestampData value_;
...

public:
    void SetPrice(double price) {
        price_ = price;
    }

    void SetAmount(double amount) {
        amount_ = amount;
    }

    double GetValue() {
        if (value_.GetTimestamp() < price_.GetTimestamp()
            || value_.GetTimestamp() < amount_.GetTimestamp()) {
            value_ = price_.GetValue() * amount_.GetValue();
        }
        return value_;
    }
}

优点:

  • setter 与选项 1) 一样清晰

缺点:

  • 时间戳跟踪可能很耗时

这只是一个简单的例子,我还有一个类 Portfolio 像这样:

class Portfolio {
private:
    double valueOfPositions_
    std::map<std::string, Position> positions_
...
}

valueOfPositions_positions_ 之间应该有同步机制。

您如何称呼 value_valueOfPositions_ 这样的成员?对我来说,他们就像其他成员的 view 成员。

您处理这种情况的最佳做法是什么?

1 个答案:

答案 0 :(得分:2)

好的,您在 Position 类中列出了 4 种处理值的方法。我将暂时忽略第 4 个,因为 Timestamp 属性增加了另一层复杂性(您的前 3 个选项也没有 Timestamp 属性)。

在 1st 3 个选项之间,第一个选项(价格和金额的简单设置器,以及价值的 getter 函数)是最干净的,正如您所描述的原因 - 它是如此清晰和简单。 (哪个解决方案在 3 个月后最容易理解?)

经历你描述的缺点:

  • getter 会很耗时:实际上,价格和数量相乘在计算上非常简单,而且在所有其他解决方案中,您仍然必须进行乘法,只是在不同的点。保持乘法简单和包含(仅在调用 GetValue() 时)意味着您可以控制执行乘法的频率 - 在其他示例中,例如在选项 2 中,每次更新价格或金额时,都会再进行一次乘法运算。

  • 如何处理多个位置和总值:将所有逻辑放在 Portfolio 类中,或者任何包含 Position 对象数组的类 - 初始化一个 GetTotalPositionValue() 函数。在保存 Position 对象的任何数据结构中为多个 Position 对象设置逻辑要干净得多,而不是在 Position 对象本身中设置一些逻辑。

至于添加时间戳,您似乎希望每个 Position 对象都有一个 timestamp 变量,以及其他一些函数,例如GetTotalPositionValueWithinRange() 函数,根据它们的 timestamp 变量获取 Position 对象的子集。 timestamp 似乎也是 Position 对象的一个​​属性,与价格和金额处于同一级别 - 每个 Position 对象都有一个价格、金额、值和时间戳。

希望能回答您的问题 - 我并不总是最擅长解释设计决策,所以我希望我足够清楚。

相关问题