Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Design patterns 当一个操作需要传递的不仅仅是结果时,您是tuple/throw/还是getcontext?_Design Patterns_Architecture_Tdd_Exception_Single Responsibility Principle - Fatal编程技术网

Design patterns 当一个操作需要传递的不仅仅是结果时,您是tuple/throw/还是getcontext?

Design patterns 当一个操作需要传递的不仅仅是结果时,您是tuple/throw/还是getcontext?,design-patterns,architecture,tdd,exception,single-responsibility-principle,Design Patterns,Architecture,Tdd,Exception,Single Responsibility Principle,我试图重构一些“发送电子邮件”代码,方法是将这些步骤(验证、附加相关内容、格式、发送)划分为单独的类,这些类可以更容易地测试、记录和更新 作为这项工作的一部分,我必须找出一种方法,让操作人员将验证或暂时性错误(“该项目已被删除”)反馈给发起人,以便发起人可以要求用户提供更多信息或告诉他们坏消息。这是线程所走的路径(耶,一个涂鸦) “控制器” . -> 发件箱 . -> 验证器 . -> 格式化程序 . -> 发件人 . 参数,正在进行的工

我试图重构一些“发送电子邮件”代码,方法是将这些步骤(验证、附加相关内容、格式、发送)划分为单独的类,这些类可以更容易地测试、记录和更新

作为这项工作的一部分,我必须找出一种方法,让操作人员将验证或暂时性错误(“该项目已被删除”)反馈给发起人,以便发起人可以要求用户提供更多信息或告诉他们坏消息。这是线程所走的路径(耶,一个涂鸦)

“控制器”
.   -> 发件箱
.         -> 验证器
.         -> 格式化程序
.         -> 发件人
.    参数,正在进行的工作

也许问题在于行动的顺序,这使得下一个行动电话

另一种方法是让控制器依次调用所有动作。在这种情况下,控制器和每个动作之间存在直接关系

每个操作可能返回一个简单的结果,或通过适合其情况的方式发出错误信号:

  • 通过异常的异常情况
  • 通过空返回没有结果
从一个动作到另一个动作的重用可以作为局部变量发生

示例代码(根据需要添加参数等):

类控制器1{
private Sender=new SenderImpl();
公共作废处理(字符串文本){
试一试{
发件箱=发件箱();
列出错误=验证(文本);
如果(!errors.isEmpty()){
....
返回;
}
字符串格式化=格式(文本);
send.send(格式化);
}捕获(MyException e){
....
}
}
}

尽管在这段代码中,这些步骤被委托给同一类的方法,但对于其他类的实例,遵循相同的结构是非常容易的(但仅在需要时,不要过度设计)。正如您提到的,这可以证明是可测试的。我更改了
发送方的示例代码

您可以将模式与以下模式一起使用:

控制器将成为模板方法。对于电子邮件发送过程的每个步骤,您都会调用一个实现该步骤的委托/策略类

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);
        }
    }
}
当代码必须偏离快乐路径时,我更喜欢使用异常。我觉得它们将逻辑和错误处理清晰地分开

编辑:SendMessage方法的返回向调用方指示验证是否通过,以及验证中失败的内容。然后,调用方可以提示用户提供更多信息并重试,或者指示成功。只有在真正异常的情况下才会抛出异常


使用这种方法,您的算法的每个组件都可以独立地模拟和测试,任何策略都不需要知道其他任何策略是如何工作的,也不需要知道如何处理其他人的错误。最后,你所有的错误处理都集中在一个地方。

好的一点,让行动称他们的前辈很难闻,谢天谢地,这只是我拙劣涂鸦技能的产物。到目前为止,我已经用发件箱封装了这些步骤,并按顺序调用了每一个步骤。我也同意try{}catch作为引用和返回的组合用于异常情况和输入/输出是有意义的。我仍然需要捕获的位是当操作输入的类型与其输出的类型不同时。var email=格式化程序(emailParameters);这意味着我必须决定列表是返回的一部分还是传递给每个人。@james感谢您的评论。如果您需要对某个特定部分提出更具体的意见,请让我们知道。很好,这与发件箱的意图非常吻合,很高兴知道它有一个名称。我喜欢“快乐路径”的想法,但如果验证出错,抛出像UserForgortReturnAddress这样的异常会让人感觉“响亮”。我有一种毫无帮助的愿望,希望看到重试是快乐之路的一部分(选项B)。我更新了代码,只在真正异常的情况下使用异常。如果验证失败,在重试之前需要提示用户提供更多/正确的信息。+1用于混合异常和返回代码:我通常在代码出错时抛出(例如,错误的假设),并使用返回代码进行用户验证。
    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) {
           ....
         }
       }
    }
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);
        }
    }
}