一系列操作的最佳OOP设计模式


11

我正在开发一个应用程序,该应用程序的模块按顺序执行以下财务操作:

当用户要求将一定金额转入她的银行帐户时:

  1. 检查现在是否可以进行任何交易?(交易只能在特定时间段内进行)
  2. 检查用户是否已要求提取最低金额
  3. 检查用户是否具有任何默认帐户

以上所有操作的结果均应记录。

如果满足以上所有条件,则执行交易。将来可能还会有其他检查。

哪种面向对象设计模式最适合上述情况?


3
永远不要寻找解决问题的设计模式。使用设计模式传达正确的解决方案。developers.stackexchange.com/questions/70877/…遵循SOLID原则,您不会出错。
pdr

2
我不同意。模式的名称可以简化通信,还应该使用它们来传达解决方案。但是我不同意“永远不要寻找解决问题的设计模式”。它们不仅解决特定的问题,而且处理不同的力量和约束。看看“代理”和“装饰器”。它们看起来相似,但解决了不同的问题。因此,我认为,在您自己解决问题之前,至少应该了解一下众所周知的设计模式,以便从中获利,一种解决问题的标准方法以及一种简单的沟通方式。
强尼迪

10
这很好地说明了模式的含义:“它们(模式)为在软件开发过程中(从组织到编程环境)在某些情况下反复出现的问题提供了有效,具体和适应性强的解决方案。” [POSA5,第 30]因此,从这个角度来看,很明显,寻找一种模式作为一种适应性解决方案是一种正确的方法。
强尼·迪

3
您是否正在请求一个面向对象的构造来描述简单的旧过程编程?
mouviciel 2013年

4
遵循KISS原则。到目前为止,您的问题可以用一个方法中的3个“ if”语句解决。不要仅仅为了酷而尝试使用设计模式。每次您编写其他课程时,请始终思考:我真的需要吗?
Eiver

Answers:


13

听起来您正在寻找的是责任链。在这种情况下,您可以拥有以下课程:

  • TransactionValidatorBase 抽象基类
  • TransactionTimeValidator
  • TransactionAmountValidator
  • TransactionAccountValidator

它们链接在一起以应用您指定的许多规则。

读进一步


11
我的理解是,责任链更像是一个过滤器-即我们沿着责任链向下走,直到找到有能力应对责任的人,然后“链接”将负责责任并退出。实际上,COR的一个缺陷是很难使它返回一个值,这似乎是您可能需要的。
艾米·布兰肯希

我认为您可以拥有一个单层的R链。我真的不觉得很难从Chain链中返回值,并且会有一点点吸引力。给定每个级别都必须向上通信,以遵守某个特定的原始接口,并且将需要接受来自下面的输入,前提是此类输入符合原始接口。当在更紧密耦合的两个Chain级别之间需要接口丰富度时,可以对Abtract进行多态变形以支持它。
Andyz Smith,

3

如果您的步骤序列主要执行验证职责(看起来像您一样),而又不改变输入内容,那么我认为确实是“责任链”模式,如@pswg在他的回答中所述

但是,由于您的问题有点笼统,因此我也想添加“管道处理”,因为有了这一点,一个步骤将产生一个输出,该输出将成为下一步的输入(因此将原始输入变异) 。

这是关于它的两篇文章:
Martin Fowler的管道收集
关于该模式的更多理论讨论


2

正确的模式实际上取决于上下文。在选择要遵循的任何特定模式之前,我将尝试找出这些问题的答案:

  • 是否需要在运行时创建(1,2,3)检查的不同组合?
  • 他们是否需要相同的变量来执行其操作,或者它们有很大不同?
  • 错误消息应该有多精确?
  • 如果发生故障,用户是否总是从第一步开始重试?
  • 如何处理并发?
  • 每种方法都会向请求中添加某些内容还是只是进行验证?(例如默认帐户ID?)

基于直觉,我会将它们编码为带有错误代码聚集参数的简单方法。

public void DoTransaction(IErrorAgregator error, TransactionRequest request)
{
    if(!IsTransactionInCertainTimePeriod(request, error)) return;
    if(!IsTransactionAmountInUserBounds(request, error)) return;
    if(!UserHaveDefaultAccount(request, error)) return;
    bankingTransactor.PerformTransaction(request);
}

最好将DoTransaction放入“ ITransactionValidationStragegy”接口,并创建一个包含验证样板代码的超类型层。

但是,在这种设计中,我假设验证逻辑是在编译时确定的。


0

尽管这里已经提到了这些模式,但是我建议您根据所使用的框架来考虑如何在应用程序中使用它们。

例如,您想要执行的验证很可能会随着时间的推移而不断变化(可能是您想在以后添加新的验证,以将交易限制为每天10次)。另外,您可能不想在实际业务服务或集成代码开始之前进行验证。如果可以将验证添加为可配置验证,那将是很好的。

如果您正在使用Struts,则使用拦截器可能是一个好主意。在春季的情况下,bean注入作为依赖项可以为您提供更大的灵活性。我的建议不仅是查看模式/习惯用法,还要查看用于构建应用程序的框架,并从未来派的角度来看如何最好地满足您的需求。


-2

根据我的理解,所需的任何内容都可以安装到以下命令模式中。可以按照以下步骤进行课程设计。

interface Transaction{
void performAction();
}

class Banking{

void moneyValidation(){
//Validate Here
}

void timeValidation(){
//validate Here
}
}

class TimeValidation implements Transaction{

public Banking bank;

public TimeValidation (Banking bnk){
bank=bnk;
}

void performAction(){
bnk.timeValidation();
}


class MoneyValidation Implements Transaction{

public Banking bank;

public MoneyValidation(Banking bnk;){
bank=bnk;
}

void performAction(){
bnk.moneyValidation();
}
}


class Control{

private List val_list=new ArrayList();

void storeValidation(Transaction trans){
val_list.add(trans);
trans.performAction(val_list.getFirstAndRemove());
}
}

//Same for other validation classes

您的Client类将包含以下代码片段:

Banking bnk = new Banking();
MoneyValidation m_val = new MoneyValidation (bnk);
TimeValidation t_val = new TimeValidation (bnk);
Control ctrl = new Control();
ctrl.storeValidation(m_val);
ctrl.storeValidation(t_val);

根据我的理解,这是上面给出的方案。


这很糟糕,因为当金钱验证失败时,时间验证是没有用的,但是无论如何都会完成
Ewoks 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.