代码之家  ›  专栏  ›  技术社区  ›  KaptajnKold

模式来处理可能有不同类型结果的函数

  •  4
  • KaptajnKold  · 技术社区  · 14 年前

    假设您在一个对象上有一个方法,该方法通过给定一些输入来改变对象的状态 输入根据一些复杂的逻辑进行验证。

    现在假设当输入无法验证时,可能是由于几个不同的原因,我们希望能够以不同的方式处理每一个问题。

    但我对使用异常的保留意见是,在某些情况下,输入没有被验证没有什么异常,我真的希望避免使用异常来控制程序的预期流中的内容。

    如果只有一种解释可能,我可以简单地选择返回一个布尔值,该值指示操作是否导致状态更改,并在没有改变时进行适当的响应。

    当然,也可以选择返回一个状态代码,然后客户端可以选择是否解释该代码。我也不太喜欢这样,因为状态码没有任何语义。

    到目前为止,我的解决方案是始终检查我能够处理的每一种可能的情况 之前 我调用该方法,该方法返回一个布尔值,以通知客户机对象是否更改了状态。这使我能够灵活地处理尽可能少的或尽可能多的情况,这取决于我所处的环境。它还可以使我调用的方法更易于编写。缺点是无论我在哪里调用方法,客户端代码中都存在大量重复。

    5 回复  |  直到 14 年前
        1
  •  1
  •   Community CDub    7 年前

    物体

    这与中描述的“跟踪器”思想类似 mdma's answer . 状态对象被内省的深度取决于客户端。一个不在乎细节的客户可以检查 status.was_successful() 方法。不同的是,我将直接返回“tracker”,而不是将其作为引用传入。这使得调用接口更加简单。

        2
  •  1
  •   mdma    14 年前

    返回值不是该方法唯一的out值,您可以使用“out”参数,或者将其他对象作为引用传递。例如,除了要验证的输入之外,您还可以向方法传递一个附加的对象-“跟踪器”,该方法会用输入的有效性和状态更改的详细信息填充该对象。

    您仍然可以保留布尔值作为一般的成功/失败标志。有些客户机可能不关心细节,只依赖于返回值,为跟踪器传递一个空引用。其他客户端可能需要所有详细信息,因此只使用跟踪器来确定状态是否已更改。

    关键的是,通过允许客户机传入跟踪程序,客户机可以指示要收集多少详细信息,并决定如何处理这些信息。其中一些可能计算成本很高,或者需要占用大量内存。使用tracker作为参数,而不仅仅是返回值,允许客户机提供最合适的实现。tracker类可以包含客户机设置的标志和其他信号,这些信号向验证器指示客户机希望从验证中获得什么信息。

    为了方便起见,您还可以使用一个返回跟踪器的方法,但这实际上是语法上的甜点。E、 g.(在psudo java中)

       interface ValidationResult  {
          List<ValidationError> validationErrors();  
          boolean isValid();      
          List<StateChange> stateChanges();
          boolean hasChanged();
       }
    
       public class AbstractValidationResult extends ValidationResult {
          // provides setters for properties. Make setter available to
          // the StateChangeValidator, but hides these from the ValidationResult
          // interface that general clients use.
          public void setValid(boolean valid) {
              this.valid = valid;
          }
       }
    
       class DefaultValidationResult : AbstractValidationResult {
           // default implementation
       }
    
       // your input validationg/state changing class
       class StateChangeValidator 
       {
            // convenience method
            public ValidationResult setState(Input intput)
            {
               return setState(input, new DefaultValidationResult());
            }
    
            // implementation allows clients to specify how the validation is handled.
            public ValidationResult setState(Input input, AbstactValidationResult result)
            {
               validate(input, result);
               changeState(input);
               return result;
            }
    
            // just validation - no actual state change
            public ValidationResult validate(Input input, AbstractValidationResult result)
            {
               result.setvalid(!hasErrors);
               return result;               
            }
       }
    

    无论您选择哪种方法,您都应该能够避免在类之外重复验证行为。

    在对象上分离出一个“validate”方法也很有用,该方法可以验证输入,但实际上不会改变状态。当预先验证输入时,例如在UI中启用OK按钮时,此模式非常有用。

        3
  •  0
  •   Savageman    14 年前

    UPLOAD_ERR_INI_SIZE , UPLOAD_ERR_FORM_SIZE 等等。当然,当你使用诸如1、2、3这样的简单数字时,它会变得混乱,因为你不知道它们的意思。但是常量为状态代码提供了一种优雅的方式来表达某种意义。

        4
  •  0
  •   Arseny    14 年前

    为什么不使用策略或模板方法模式之一呢。 我会选择模板方法。假设你的函数有复杂的逻辑,输入参数是一个接口

        5
  •  0
  •   mathk    14 年前

    On think可以使用lambda/closure(取决于您需要什么)。 在smalltalk这里你做什么。

    dic at: #foo ifAbsent: [ 'do something interesting' ]
    

    在这里你可以看到,每当你在字典里找不到什么东西时,你就对块进行求值。 这可能适用于您的问题:每当您不验证输入时,请询问发送者通过评估闭包来做什么。