【问题标题】:Ruby design pattern: holding multiple types of objects in one classRuby 设计模式:在一个类中保存多种类型的对象
【发布时间】:2011-09-11 14:10:42
【问题描述】:

我正在 Rails 中构建复式记账系统,其中包括:

  • 用户。属性:user_id。关系:has_many:帐户
  • 帐户。属性:user_id。关系:belongs_to :user、posts
  • 杂志。属性:身份证。关系:has_many :posting,belongs_to :period
  • 发布。属性:journal_id、account_id、积分。关系:belongs_to :journal, :account。

对于从账户 1 到账户 2 的每一笔交易,将有两个过账,一个在账户 1 和一个在账户 2,以及一个日志对象来描述整个交易。

account中的主要方法是:

def transfer (destination, amount, description=nil)
  Journal.transfer self, destination, amount, description
end

从 Journal 调用 transfer 方法生成 Postings:

def self.transfer( source, destination, amount, description=nil)
     transaction do
          j = create! :description => description, :period_id => p.id
          Posting.create! :journal_id => j.id, :account_id => source.id,  
                          :points    => -Integer(amount)
          Posting.create! :journal_id => j.id, :account_id => destination.id, 
                          :points =>  Integer(amount)

在此处查看有关此系统的更多详细信息:http://homepages.tcp.co.uk/~m-wigley/gc_wp_ded.html

现在,问题是我想允许账户 1 向账户 2“质押”一些积分。通过质押,账户 1 将不再有权访问这些积分。如果稍后账户 1 授权交易,那么账户 2 可以使用这些积分。

我只能想到一种方法来解决这个问题(向this discussion学习):

为每个用户创建两个帐户,“已结算”和“已抵押”。 1质押时,积分从1的结算账户转移到2的质押账户。当1批准后,积分将从2的质押账户转移到结算账户。

为了实现这一点,我在 Account, enum 中添加了一个“account_type”列,其中包含“pledged”和“settled” 但是,看起来不太对,因为当用户要进行质押时,他必须找出他应该从哪个账户类型发送积分,以及他应该发送到哪个类型的账户。由于这一变化,账户现在不能像以前那样代表用户做出转账决定,因为每个用户都有多个账户。

现在,我可以向 User 类添加转账功能,然后它将选择他拥有的 account_type,然后从该账户发送积分。但我不希望金融系统和我系统的一般部分之间存在紧密的耦合。

我可以添加一个“包装器”类AccountManager,它与User 具有一对一的关系,用户可以选择从哪个帐户发送点。但这似乎有点不必要的复杂。

我还可以添加转账、结算的方法类,它会查找合适的账户类型进行转账。但它看起来也不对。

我不认为我可以修改 Posting 以便它可以顺利处理这个问题,但我可能错了。

所以我想听听您对我应该如何解决这个问题的建议。

谢谢。

【问题讨论】:

    标签: ruby-on-rails ruby design-patterns


    【解决方案1】:

    用户实际上并没有两个帐户(或帐户类型),而是有待处理或已完成的转移。当我在银行工作(特别是信用卡/借记卡支付处理)时,一切都是这样处理的,因为有些资金每 n 小时通过批处理文件转移一次。

    简而言之,有一个中间步骤。初始付款会从 1 的帐户中扣除款项。在 2 的银行收到资金请求并对其进行处理之前,资金请求被标记为待处理。一旦处理完毕,资金申请就完成了,一切都应该如此。

    如果由于某种原因出现退款或其他原因,则资金请求将被取消,资金将退还给 1

    这个过程是异步发生的(很明显),但与实时请求并存。在我们的系统中以相同的方式表示,但它不需要 - 在您的情况下,您可以像现在一样处理直接转账,并使用两步流程处理承诺。

    在我们的系统中,资金请求处理充当日志——我们可以通过查看资金请求更新历史记录来重新创建/跟踪任何付款的路径。我不确定在您的系统中处理它的最佳方法是什么;我最初的猜测是有一个用于撤回的日志条目和一个用于接受的日志条目,并且具有表明它们是两阶段转移的一部分的状态。

    不确定这有多大帮助,但这是在现实生活中处理这种情况的一种方式(或多或少)。

    【讨论】:

    • 非常感谢,戴夫。我觉得你说的很有道理。我正在考虑修改过帐,使其具有两种类型,质押和结算。帐户方法已修改为包括 transfer_type。帐户聚合方法相应修改(例如,account.available_balance 应仅从已提交的过帐中汇总)。
    • 很高兴我能帮上忙——我不确定我说的是否有意义;我工作的系统通常给我留下的问题多于答案......这让我感到惊讶的是,我们的任何钱都在任何地方
    • 我认为在我的情况下,我(管理员)在交易双方都有账户信息。因此,它更容易,因为我只需要在发送前检查一次余额。接收方保证发送方有足够的余额。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多