面向对象的对象之间交互的样式编程

时间:2010-09-19 02:51:57

标签: language-agnostic oop

我正在尝试以面向对象的方式编写程序。编码两个对象之间的交互时,我有一些困惑。

方案: 人(约翰)给人(贝蒂)5美元。

可能的解决方案(伪代码):

A)John.pays(Betty,5);
B)Betty.receives(John,5);
C)Bank.transfer(John,Betty,5);
d)
开始交易:
    John.decrease(5);
    Betty.increase(5);
结束交易:
E)Service.transferMoney(John,Betty,5); //服务是通用服务对象

请告诉我哪一种是以OOP方式编码的更合适的方式,以及背后的原因。我正在寻找一些指导,如“告诉,不要问”规则。

感谢。

11 个答案:

答案 0 :(得分:10)

我注意到的一件事是,那些不熟悉OOP的人会试图将物理世界映射到他们正在编写的代码中。你真的在乎约翰和贝蒂是人还是你真的想要描绘一个银行账户?我认为你在示例中选择的对象实际上使得更难找出问题的解决方案。

这个的重要部分是 1)在哪里提出如何移动钱的逻辑。 2)在哪里存储每个人有多少钱的数据。

您需要决定是否要在银行的个人或客户(可能是个人,公司或其他人)的背景下谈论问题。我猜你是在谈论一个客户,因为假设它是一个人会限制和误导。此外,银行是一个非常通用的术语,它是内部有人的大砖建筑物,还是具有不同页面的不同页面的在线网站。 银行帐户对象可以有一个方法(可能是静态的,具体取决于您决定存储数据的方式以及您将使用对象的所有内容),该方法知道如何从一个帐户转移到另一个帐户。如何转让的逻辑不属于贝蒂或约翰或银行,它属于银行账户,如果涉及费用等,则可以根据账户类型具有特殊逻辑。如果你把这个逻辑提供给银行,你最终会得到一个巨大的银行类,其中包括从贪婪的客户到处理特定账户类型的资金等各种方法。我对每种帐户类型都有不同的处理转移规则。想想您可能希望将转账或存款显示为待处理的时间。

如果您只是解决转移资金的问题,则无需创建一堆对象。根据已知要求和假定的未来要求,以下将是一个不错的选择。 CheckingAccount.Transfer(johnsAccountNo,bettysAccountNo,amount)

答案 1 :(得分:3)

我现在可以问一个问题吗?谁控制了钱? John决定交易金额,Betty或某些未指明的第三方吗?

我问的原因是因为这里没有真正对错的答案,只有一个可能比其他答案更灵活或更强大。如果这是一个真实的生活情况,那么我会将交易建模为双方在收益之前必须达成一致的事情,以及花钱的人(约翰)启动它。回答 C 和@Mysterie Man

tx transaction_request = John.WantsToBuyFor(5);    //check if John can
if( Betty.AgreesWith( transaction_request ) )      //check if Betty wants
{
   transaction_request.FinalizeWith(Betty);        //Do it with Betty
}

并且FinalizeWith函数执行数学

void FinalizeWith(Person party)
{
    requestor.cash -= amount;
    party.cash += amount;
{

当然,您可能想要添加一些约翰购买物品的描述。

答案 2 :(得分:3)

这个问题的答案是一个漫长而复杂的问题,你会从很多人那里得到点点滴滴。为什么只是点点滴滴?因为正确答案几乎完全取决于您的系统要求。

然而,您必须确保不陷入的一个陷阱是this one。阅读你在这里得到的答案。你会得到很多好建议。 (最多关注已经被投票的建议。)一旦你阅读并理解了这些建议,read Steve Yegge's rant(并理解它!)也是如此。从长远来看,它将为您节省成本。

答案 3 :(得分:2)

我不会投票支持上述任何一项:)

为什么约翰付贝蒂?这是一个重要的问题,因为它解释了切入点的位置。让我们说约翰欠贝蒂的钱,这是发薪日。

public class John
{
    public void onPayday()
    {
        Betty.Receive(5.0f);
    }
}

当然,如果您想采用纯对象交互式方法,那就是这样。

这里的不同之处在于我们没有一个外部例程来协调John和Betty之间的交互。相反,我们让约翰回应外部事件,并选择何时与贝蒂互动。这种风格也可以很容易地描述所需的功能 - 例如“在发薪日,约翰应该支付贝蒂。”

这是控制反转意味着什么的一个很好的例子 - 对象彼此交互,而不是被某些外部例程操纵。这也是Tell,Do not Ask的一个例子,因为对象是告诉彼此的事情(John告诉它是发薪日,John告诉Betty要接受5美元)。

答案 4 :(得分:2)

这里有许多替代解决方案。例如,

Betty.Receieves(John.Gives(5))

这假设Gives函数返回给定的数量。

tx = CashTransaction(John, Betty);
tx.Transfer(5);

这假定第一个参数是Payor,第二个是Payee,那么您可以在不创建新对象的情况下执行多个事务。

可以通过多种方式对事物进行建模。您应该选择最接近您想要建模的那个。

答案 5 :(得分:2)

纯OOP的一个属性可以帮助轻松通过雷达的示例,但object-capability模型明确并以中心为中心。链接文档(“从对象到功能”(FOtC))详细介绍了主题,但(简而言之)功能的一点是,对象影响其世界的能力仅限于它所引用的对象。这一开始可能看起来不那么重要,但在保护访问权限方面非常重要,并且会影响其他类方法中类的哪些方法可用。

选项A)授予帐户John访问帐户Betty,而选项B)授予Betty访问帐户John;两者都不可取。使用选项C),帐户访问权限由银行调解,因此只有银行可以窃取或伪造资金。选项D)与其他三个不同:其他选项显示正在发送的消息但不显示实现,而D)是一个方法实现,它不显示它处理的消息,也不显示它处理它的类。 D)可以很容易地实现前三个选项中的任何一个。

FOtC开始提供包含其他几个类的解决方案:

  • 封口机& unsealers,
  • 钱包,有点像帐户,因为它们包含钱但不一定拥有所有者。
  • mints,这是唯一可以创造积极余额钱包的东西

薄荷有一个封口机/开封器对,每当薄荷创造一个时,它就会赋予钱包。钱包监督平衡变化;他们在减少余额时使用封口机,并将开封从一个钱包转移到另一个钱包。钱包可以产生空钱包。由于使用了密封剂和unsealers,钱包只适用于同一薄荷创造的其他钱包。有人不能写自己的钱包来伪造钱财;只有获得薄荷的物品才能赚钱。通过限制对薄荷糖的访问来防止伪造。

任何有钱包的人都可以通过生成一个空钱包并将钱从第一个钱包转入其中来启动交易。然后可以将临时钱包发送给收件人,收件人可以将钱从临时钱包转移到其拥有的其他钱包。通过限制对钱包的访问来防止盗窃。例如,银行代表账户中的客户持有钱包。由于银行只能访问其客户账户和临时钱包的钱包,因此只有客户的银行可以从客户那里窃取(尽管请注意,在银行账户之间的转账中,有两个客户可能成为受害者,因此有两个潜在客户盗贼)。

该系统缺少一些重要的细节,例如货币当局(其中包含对一个或多个薄荷的引用)以创造资金。

总而言之,货币交易安全实施起来很棘手,因此可能不是学习OOP基础知识的最佳范例。

答案 6 :(得分:1)

如果您真的想要获得OOPy,请尝试以下

Person       Betty,John;
CashTransfer PocketMoney;
PocketMoney.from   = John;
PocketMoney.to     = Betty;
PocketMoney.amount = 20.00;
PocketMoney.transfer();

OOP的目的不是让代码更像是书面语言,而是让对象具有不同的方法和参数,使代码更具可读性。

所以从上面的代码中,你可以看到约翰给贝蒂20美元的零用钱。代码是有意义的,允许更容易的代码可读性和可理解性。

答案 7 :(得分:0)

我的投票:C。C做D做的事情(例如不赔钱等)。

在这个小例子中,“银行”是一个完全有效的实体,知道约翰和贝蒂有多少钱。约翰和贝蒂都不应该骗到银行。

不要害怕根据情况需要反转(或不反转)“OO”程序中的逻辑。

答案 8 :(得分:0)

您应该根据您的域进行建模。选项C看起来是最佳选择,因为它将事务逻辑分离到Bank \ Service类。

答案 9 :(得分:0)

这是一个我作为新手程序员经常与自己斗争的问题。我同意“C”似乎是最好的选择。在这样的事情中,我认为最好使用“中性”实体,例如“银行”。这实际上模拟了大多数重要的现实交易,因为大多数进口交易都使用支票和/或信用(中立的第三方)。

答案 10 :(得分:0)

对OOP不熟悉并最终使用一些OOP,我会说它应该是A和B.

我们专注于人,每个人都可以自己处理他的钱。我们不知道他是否会使用银行,或者他是否只是直接从贝蒂那里获得现金。

您创建了一个Person类,并使用两种方法向该类添加方法:send和recieve。它还必须有一个名为balance的公共var来跟踪它们的余额。

你创建了两个Person对象:Betty和John。相应地使用方法。像John.sends(Betty,5)。这应该创建Betty并更新Betty的余额。

如果他们想要使用银行怎么办?添加另一种方法,比如说......转移(acct)它是什么。

这就是我的想法。