如何为抽象方法编写合同?

时间:2010-08-18 10:08:53

标签: java design-patterns design-by-contract

我在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的输出是否满足合约的好方法(在这种情况下,最后一个char必须是新行char)。

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

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 个答案:

答案 0 :(得分:3)

这看起来像是使用Template Method design pattern的地方。使用模板方法模式,可以在抽象类中实现和最终确定通用算法,而某些细节可以在子类中实现。

为了实现Template方法:

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

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

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";
     }
}

答案 1 :(得分:1)

就是这样。你必须创建你的方法并在其上使用final修饰符,这样任何人都无法重写合同。在这种方法中,您检查合同并调用内部方法(您的generateLineHook(String)),无需再做任何事情。

答案 2 :(得分:1)

我相信这样做很好,只记得在公共方法中添加“final”,这样子类就无法覆盖你的检查。

答案 3 :(得分:0)

我经常使用代码合约,有时会有很好的定义和自我描述的方法,很难签订合同。

我不知道Java(我假设您正在使用iContract等),但在C#/ Code Contracts中我会这样做:

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

或类似的......

我不确定你有什么更好的方法来表达你的意思。