我正在尝试通过将步骤(验证,附加相关内容,格式,发送)分成可以更容易测试,记录和更新的单独类来重构某些“发送电子邮件”代码。
作为其中的一部分,我必须找出一种方法让操作将验证或瞬态错误(“该项目被删除”)传回给发起人,以便它可以向用户询问更多信息或告诉他们坏消息。这是线程所采用的路径(yay,一个涂鸦)
"Controller"
. -> Outbox
. -> Validator
. -> Formatter
. -> Sender
. <-
-> Parameters, work in progress
<- Good, not so good, "you better sit down" news
所以你是一个深思熟虑的,在“回归”,“例外”或“背景”之间...哪一个让你最开心?
一个。在任何问题上抛出异常,让控制器将它可以优雅处理的那些和知道我“蜂鸣器”的那些分开。
B中。 返回某种结果
<T>
类,用于携带操作的产品(电子邮件)和各种操作的枚举结果。℃。将上下文传入/移出所有可以指示无法处理的参数的步骤,并使方法签名非常简单。
d。儿子,你是在思考这个问题。以下是你要做的事情:
<
YourSpecialJujuHere/>
感谢所有的贡献,你摇滚乐。
答案 0 :(得分:4)
您可以将Template Method模式与Strategy模式一起使用:
您的控制器成为模板方法。对于电子邮件发送过程的每个步骤,您将调出一个实现该步骤的委托/策略类。
public class EmailSender
{
private iOutboxGetter outboxGetter;
private iMsgValidator validator;
private iMsgFormatter formatter;
private iMsgSender sender;
//setters for each stragegy, or a constructor
//good use for IOC container
public iSendResult SendMessage(iMsgParams params)
{
try
{
var outbox = outboxGetter.getOutbox(params.outbox);
var validationResults = validator.validate(params);
if(validationResults.IsValid)
{
var msg = formatter.formatMsg(params.message);
sender.send(msg);
return new AllGoodSendResult();
}
else
{
return new ValidationFailedSendResult(validationResults);
}
}
catch(CatastrophicException e)
{
Pager.SendCriticalPage(e.message);
return new CatistrophicFailureSendResult(e);
}
}
}
当代码必须偏离Happy Path时,我更喜欢使用异常。我觉得他们保持逻辑和错误处理完全分开。
编辑:SendMessage方法的返回向调用者指示验证是否通过,以及验证失败。然后,呼叫者可以提示用户提供更多信息并重试,或指示成功。只有在真正异常的情况下才会抛出异常。
使用这种方法,您的算法的每个组件都可以独立进行模拟和测试,没有策略需要知道其他策略是如何工作的,也不需要知道如何处理其他人的错误。最后,您的所有错误处理都在一个地方进行了中心化。
答案 1 :(得分:1)
也许问题在于动作的排序,这使得动作调用成为下一个动作。
另一种方法是让Controller依次调用所有操作。在这种情况下,您的Controller与每个操作之间存在直接关系。
每个动作都可能返回一个简单的结果,或通过适合其情况的方式发出错误信号:
从一个动作重用到另一个动作可以作为局部变量发生。
示例代码(根据需要添加参数等):
class Controller1 {
private Sender sender = new SenderImpl();
public void process(String text) {
try {
Outbox box = getOutbox();
List<Errors> errors = validate(text);
if (!errors.isEmpty()) {
....
return;
}
String formatted = format(text);
sender.send(formatted);
} catch(MyException e) {
....
}
}
}
虽然在此代码中,步骤被委托给同一个类的方法,但是很容易跟随其他类的实例使用相同的结构(但仅在需要时,不要过度工程)。正如您所提到的,这对于可测试性来说是合理的。我更改了sender
的示例代码。