4

我在我的 Java 项目中使用合同。(合同 = 在方法的开始和结束时进行检查)

我想知道是否有一种很好的方式/模式来为通用方法编写合同。例如:

public abstract class AbstractStringGenerator{
    /**
     * This method must return a new line as it's last char
     * @return string output
     */
     public abstract string generateLine(String input);
}

我想要的是一种检查输出是否generateLine满足合同的好方法(在这种情况下,最后一个字符必须是新行字符)。

我想我可以做到这一点(但我想知道是否有更好的方法);

public abstract class AbstractStringGenerator{

     public string generateLine(String input){
         string result = generateLineHook(input);
         //do contract checking...
         //if new line char is not the last char, then throw contract exception...
         return result;
     }
    /**
     * This method must return a new line as it's last char
     * @return string output
     */
     protected abstract string generateLineHook(String input);
}

希望这不是太模糊。任何帮助表示赞赏。

4

4 回答 4

3

这看起来像是使用模板方法设计模式的地方。使用模板方法模式,通用算法可以在抽象类中实现和完成,而一些细节可以在子类中实现。

为了实现模板方法:

  • 您需要最终确定算法,以控制子类化行为。通过禁止子类通过 final 关键字覆盖模板方法,可以确保可以在模板中实现足够的检查,以确保算法中的不变量保持良好。
  • 您需要允许子类覆盖可能会发生变化的行为。子类可以完全覆盖这种行为,并且此类方法通常在父类中是抽象的,通常作为子类可以实现钩子的地方。

Template 方法可以在您的示例中实现为

public abstract class AbstractStringGenerator{

     // marked as final. Subclasses cannot override this behavior
     public final String generateLine(String input){
         String result = generateLineHook(input);
         //do contract checking...
         //if new line char is not the last char, then throw contract exception...
         if(!result.endsWith("\n")){
             throw new IllegalStateException("Result from hook does not contain new line");
         }
         return result;
     }
    /**
     * This method must return a new line as it's last char
     * @return string output
     */
     protected abstract string generateLineHook(String input);
}


public class ConcreteStringGenerator{

    /**
     * This method overrides the beh
     * @return string output
     */
     protected String generateLineHook(String input){
         return "blah\n";
     }
}
于 2010-08-18T10:15:50.223 回答
1

正是这样。您必须创建您的方法并在其上使用final修饰符,以便没有人可以重写合同。在这个方法中,你检查你的合约并调用一个内部方法(你的generateLineHook(String)),没有什么可做的了。

于 2010-08-18T10:14:12.347 回答
1

我相信这是一个很好的做法,只要记住在公共方法中添加一个“final”,这样子类就不能覆盖你的检查。

于 2010-08-18T10:17:46.067 回答
0

我经常使用代码契约,有时有一些定义明确且自我描述的方法很难为其编写契约。

我不了解 Java(我假设您正在使用 iContract 或其他东西),但在 C#/代码合同中我会这样做:

Contract.Ensures(result[result.Length-1] == @"\n");

或类似的东西......

我不确定您所说的有更好的方法来做到这一点是什么意思。

于 2010-08-18T10:15:32.033 回答