在OOP设计团队中与小组成员合作,我有分歧,我无法在网上找到答案。
创建一个类似于非营利组织的软件,该公益组织拥有捐赠者及其信用卡。
一种方法是creditCardList
(集合类)应该只存储和返回creditCard
个对象。然后,当它们返回时,Organization
类应该为每个对象运行processCard()
作为creditCard
对象的方法。
另一方面是CreditCardList
应该处理所有并包含在集合中的所有项目上运行的循环。
一般来说什么是更好的软件设计?
答案 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
}
}
我显然不了解您的要求的所有细节,但我的观点是从您拥有的事物开始,而不是需要的技术步骤(如信用卡处理)发生。这也适用于方法名称,而不仅仅是类名!