软件设计原则:将您的集合与处理对象分开?

时间:2017-10-08 19:07:47

标签: java oop software-design

在OOP设计团队中与小组成员合作,我有分歧,我无法在网上找到答案。

创建一个类似于非营利组织的软件,该公益组织拥有捐赠者及其信用卡。

process diagram

一种方法是creditCardList(集合类)应该只存储和返回creditCard个对象。然后,当它们返回时,Organization类应该为每个对象运行processCard()作为creditCard对象的方法。

另一方面是CreditCardList应该处理所有并包含在集合中的所有项目上运行的循环。

一般来说什么是更好的软件设计?

4 个答案:

答案 0 :(得分:2)

很抱歉地说,但我不会选择这两种方法来分离职责原则。如果我正确理解了要求,则组织对象是表示接受捐赠的慈善组织的实体。 CreditCardList是用于支付处理的所有信用卡的集合。它们都不是保持支付处理逻辑的好地方。

相反,我会介绍一个名为//tr[preceding::h1[1][contains(text(), "Expense")]]/td[preceding-sibling::td/descendant-or-self::*[contains(text() , "Total")]]//*[not(*)]的新助手类。这个类有一个名为PaymentProcessor的方法。此方法应包含处理来自信用卡的付款的逻辑。使用此设计,您还可以在此课程中引入其他方法,以使用其他方式处理付款,例如直接从银行帐户或PayPal扣款。

根据OO设计原则,我们应该只为一个目的而设置一个类或接口,以提高可维护性。

我希望这可能有助于解决您与同事的建设性差异。 :)

答案 1 :(得分:2)

首先,我发现图表中的for-each调用很奇怪:为什么组织调用CreditCard.processCard方法并将creditCard实例作为参数传递?

首先,“处理信用卡”是什么意思?信用卡实例是否能够处理它? 我要做的第一个设计决定是,CreditCard对象不应该依赖某些外部服务。处理信用卡听起来像处理外部事物。 我会保持CreditCard逻辑纯净。只在此处将逻辑操作放在本地字段和属性上。

CreditCardList有一个主要任务。拿着一套信用卡。您希望检索和存储信用卡列表的方式可能会发生变化,因此最好将问题分开并将处理逻辑保留在该类之外。 在CreditCardList中运行循环的一个原因可能是,您不希望公开具体的信用卡列表。但这可以以更优雅的方式处理。定义接口ICardProcessor并将其作为构造函数参数注入到CreditCardList中。 然后,foreach可以保留在类中,并在每个实例上调用ICardProcessor.Process(card)。

答案 2 :(得分:1)

我会选择第一个选项。

由于您已将CreditCardList用作存储空间,因此该课程不应承担任何其他责任。此类的功能仅限于提供卡片(完全/部分,具有条件/按标准)。

第二种选择提出了将存储与卡处理机制耦合的问题。您的存储库现在取决于处理系统以及系统可能需要的输入参数。此外,存储确实知道它不应该知道的所有过程。

答案 3 :(得分:1)

这是另一种设计理念。我们不要只关注完成目标所需的步骤,而应该首先对问题进行建模,并使用问题的为事物提供名称。

显然有Organization个,接受Donation个。好吧,让我们试试这个:

public interface Organization {
    void accept(Donation donation);
}

public interface Donation {
}

现在,捐赠的资金可能需要在accept()方法的某个时刻转移到组织,所以让我们将其作为Donation对象的责任添加:

public interface Donation {
    void transferTo(BankReference target);
}

在示例中,您可以一次处理多个捐款。这是您询问的迭代。这将是这一课:

public final class Donations implements Donation {
    ...
    public Donations(Donation... donations) {
        ...
    }

    @Override
    public void transferTo(BankReference target) {
        donations.forEach(donation -> donation.transferTo(target));
    }
}

接下来,您希望使用信用卡进行捐赠。您可以通过提供特定的捐赠类型来实现此目的。

public final class CreditCardDonation implements Donation {
    ...
    @Override
    public void transferTo(BankReference target) {
        // Here is the credit card processing logic
    }
}

我显然不了解您的要求的所有细节,但我的观点是从您拥有的事物开始,而不是需要的技术步骤(如信用卡处理)发生。这也适用于方法名称,而不仅仅是类名!