Как я могу написать контракт для абстрактного метода? - PullRequest
4 голосов
/ 18 августа 2010

Я использую контракты в своем проекте 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 ]

3 голосов
/ 18 августа 2010

Это похоже на то место, где можно использовать шаблон проектирования Template Method . С шаблоном метода шаблона общий алгоритм может быть реализован и завершен в абстрактном классе, тогда как некоторые из особенностей могут быть реализованы в дочерних классах.

Для реализации метода Template:

  • Вам нужно будет завершить алгоритм, чтобы управлять поведением подклассов. Запретив подклассам переопределять метод шаблона с помощью ключевого слова 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";
     }
}
1 голос
/ 18 августа 2010

Я считаю, что это неплохо, просто не забудьте добавить "final" в публичный метод, чтобы подклассы не могли отменить вашу проверку.

1 голос
/ 18 августа 2010

Это именно так. Вы должны создать свой метод и использовать модификатор final, чтобы никто не мог переписать контракт. В этом методе вы проверяете свой контракт и вызываете внутренний метод (ваш generateLineHook(String)), больше ничего не нужно делать.

0 голосов
/ 18 августа 2010

Я регулярно использую контракты кода, а иногда существуют хорошо определенные и самоописывающие методы, для которых очень сложно написать контракт.

Я не знаю о Java (я предполагаю, что вы используете iContract или что-то в этом роде),но в C # / Code Contracts я бы сделал:

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

или что-то подобное ...

Я не уверен, что вы подразумеваете под существующим лучшим способом сделать это.

...