интерфейс и контракт: в этом примере - PullRequest
1 голос
/ 10 января 2012

, поэтому я пытался понять интерфейсы , но я почти вижу только статьи, объясняющие, "как" использовать интерфейс, моя проблема в том, чтобы понять "почему":
так что лучше использовать Interface , чем создавать и создавать подклассы класса, который может оказаться бесполезным,
поэтому мы реализуем методы интерфейса в классе, но я не понимаю, почему это хорошо,

Допустим,
класс вроде Car.java определяет весь код для создания машины
мы создаем интерфейс Working.java с несколькими методами, такими как start (), stop () и т. д.
мы реализуем методы в Diesel_Car.java, Electric_Car.java и т. д.
так что это меняет для Car.java? Это может быть не лучшим примером, так как кажется, что Car должен быть родителем Diesel_Car.java и т. Д.,
но какой смысл реализовывать методы в этих классах?
Есть ли в Car.java метод , который каким-то образом "вызывает" класс Diesel_Car.java и его методы интерфейса?

Я читал, что интерфейс похож на «Контракт», но я вижу только вторую часть этого контракта (где реализован метод), и у меня возникли проблемы с представлением, где происходит первая часть?

Спасибо за вашу помощь

Ответы [ 5 ]

1 голос
/ 11 января 2012

Я делаю еще одну попытку объяснить концепцию интерфейса как контракта.

Типичный сценарий использования - это когда вы хотите отсортировать список элементов, используя java.util.Collections: <T extends java.lang.Comparable<? super T>> void sort(java.util.List<T> ts)

что означает эта подпись?sort() метод будет принимать java.util.List<T> объектов типа T, где T - это объект, реализующий интерфейс Comparable.

, поэтому, если вы хотите использовать Collections.sort () со спискомваших объектов вам понадобятся для реализации интерфейса Comparable:

public interface Comparable<T>   {   
    int compareTo(T t);
}

Итак, если вы реализуете класс типа Car и хотите сравнивать автомобили по их весу с помощью Collections.sort (), вам придется реализовать Comparable интерфейс / контракт в классе car.

public class Car implements Comparable<Car> {
   private int weight;

   //..other class implementation stuff

   @Override
   public int compareTo(Car otherCar) {
       if (this.weight == otherCar.weight) return 0;
       else if (this.weight > otherCar.weight) return 1;
       else return -1;
   }
} 

под капотом Collections.sort () будет вызывать вашу реализацию compareTo при сортировке списка.

1 голос
/ 10 января 2012

(Очень) надуманный пример (не универсальный, обработка ошибок удалена и т. Д. Для ясности).

List theList = new ArrayList();

theList - это List, в этом случае реализовано ArrayList. Допустим, мы передаем это стороннему API, который где-то в недрах добавляет что-то в список.

public void frobList(List list) {
    list.add(new Whatever());
}

Теперь, скажем, почему-то мы хотим сделать что-то необычное для элементов, которые добавляются в список. Мы не можем изменить сторонний API. Однако мы можем создать новый тип списка.

public FrobbableList extends ArrayList {
    public boolean add(E e) {
        super.add(Frobnicator.frob(e));
    }
}

Теперь в нашем коде мы меняем список, который создаем, и вызываем API, как и раньше:

List theList = new FrobbableList();
frobber.frobList(theList);

Если бы сторонний API взял ArrayList (фактический тип) вместо List (интерфейс), мы не смогли бы сделать это так же легко. Не привязывая API к конкретной реализации, он предоставил нам возможность создать собственное поведение.

Кроме того, эта концепция является фундаментальной для расширяемого, отлаживаемого, тестируемого кода. Такие вещи, как внедрение зависимостей / Инверсия управления основаны на кодировании интерфейсов для работы.

1 голос
/ 10 января 2012

Давайте возьмем пример базового класса Car с подклассами Electric_Car и Diesel_Car и немного расширим модель.

Автомобиль может иметь следующие интерфейсы

  1. Working: с start() & stop() методами
  2. Moving: с move(), turn() & stop() методами

Car может содержать экземпляр класса AirConditioner, который также должен реализовывать интерфейс Working.

Объект Driver может взаимодействовать с объектами, отличными от Working, драйвер может start() или stop().(Водитель может запускать или останавливать автомобиль и кондиционер отдельно).

также, поскольку Driver может ходить самостоятельно (и ему не всегда нужна машина), он должен реализовать интерфейсMoving.Объект Ground теперь может взаимодействовать со всем, что реализует Moving: с машиной или водителем.

0 голосов
/ 10 января 2012

Проектирование по контракту (DbC), также известное как программирование по контракту и программирование по контракту, является подходом к разработке компьютерного программного обеспечения.Он предписывает, чтобы разработчики программного обеспечения определяли формальные, точные и проверяемые спецификации интерфейса для компонентов программного обеспечения, которые расширяют обычное определение абстрактных типов данных предусловиями, постусловиями и инвариантами.Эти спецификации называются «контрактами» в соответствии с концептуальной метафорой с условиями и обязательствами деловых контрактов. Википедия

Ярлык.

Если вы следуете хорошей практике кодирования для интерфейсов, вызнать, что интерфейс определяет контракт, которому должны соответствовать все классы реализации.

Мы разработали контрактную Java, расширение Java, в котором контракты методов указываются в интерфейсах.Мы определили три цели проектирования.

  • Во-первых, контрактные Java-программы без контрактов и программы с полностью выполненными контрактами должны вести себя так, как если бы они выполнялись без контрактов в Java.
  • Во-вторых, программыскомпилированный с помощью обычного компилятора Java, должен иметь возможность взаимодействовать с программами, скомпилированными по Java-контракту.
  • Наконец, если класс не заявляет, что он соответствует определенному контракту, его никогда не следует обвинять в невыполнении этого контракта.Абстрактно, если вызывается метод m объекта с типом t, вызывающий объект должен быть обвинен только для контрактов предварительного условия, связанных с t, а m должен быть обвинен только для контрактов постусловия, связанных с t.Эти цели разработки поднимают несколько интересных вопросов и требуют решений, которые бы уравновешивали дизайн языка с проблемами разработки программного обеспечения.В этом разделе описываются все основные проблемы проектирования, альтернативы, наши решения, наши обоснования и последствия решений.Решения не являются ортогональными;некоторые из более поздних решений зависят от более ранних.

Контракты в Java Контракта являются украшениями сигнатур методов в интерфейсах.Каждое объявление метода может содержать выражение перед условием и выражение после условия;оба выражения должны быть булевыми.Предварительное условие указывает, что должно быть истинно при вызове метода.Если это не удается, виноват контекст вызова метода за то, что он не использует метод в надлежащем контексте.Выражение после условия указывает, что должно быть истинно при возврате метода.В случае неудачи виноват сам метод, который не установил обещанные условия.Контракт Java не ограничивает выражения контракта.Тем не менее, хорошая дисциплина программирования диктует, что выражения не должны способствовать результату программы.В частности, выражения не должны иметь побочных эффектов.Выражения как до, так и после условия параметризуются по аргументам метода и псевдопеременным this.Последний привязан к текущему объекту.Кроме того, постусловие контракта может ссылаться на имя метода, которое связано с результатом вызова метода.Контракты применяются в зависимости от типа контекста вызова метода.Если тип объекта является типом интерфейса, вызов метода должен соответствовать всем контрактам в интерфейсе.Например, если объект реализует интерфейс I, вызов одного из методов I должен проверить это предварительное условие и постусловие, указанное в I. Если тип объекта является типом класса, у объекта нет договорных обязательств.Поскольку программист всегда может создать интерфейс для любого класса, мы оставляем объекты с типами классов непроверенными по соображениям эффективности.Для примера рассмотрим интерфейс RootFloat:

interface RootFloat {
    float getValue ();
    float sqRoot ();
    @pre { this.getValue() >= 0f }
    @post { Math.abs(sqRoot * sqRoot - this.getValue()) < 0.01f }
}

Он описывает интерфейс для класса-оболочки float, который предоставляет метод sqRoot.Первый метод, getValue, не имееткаратов.Он не принимает аргументов и возвращает развернутый float.Метод sqRoot также не принимает аргументов, но имеет контракт.Предварительное условие утверждает, что развернутое значение больше или равно нулю.Тип результата sqRoot это float.Постусловие гласит, что квадрат результата должен быть в пределах 0,01 от значения с плавающей запятой.Несмотря на то, что язык контракта достаточно силен, чтобы в некоторых случаях указывать полное поведение, например, в предыдущем примере, полная или даже частичная корректность не является нашей целью при разработке этих контрактов.Как правило, контракты не могут выразить полное поведение метода.На самом деле существует разница между количеством информации, отображаемой в интерфейсе, и количеством проверок, которые могут удовлетворить контракты.В качестве примера рассмотрим следующий интерфейс стека:

interface Stack {
    void push (int i);
    int pop ();
}

Поскольку в интерфейсе доступны только операции push и pop, невозможно указать, что после push верхний элемент в стеке является элементом, которыйбыл просто нажал.Но если мы добавим интерфейс с помощью операции top, которая обнаружит самый верхний элемент в стеке (не удаляя его), мы можем указать, что push добавляет элементы в верхнюю часть стека:

interface Stack {
     void push (int x);
     @post { x = this.top() }
     int pop ();
     int top ();
}

InРезюме, мы не ограничиваем язык контрактов.Это делает контрактный язык максимально гибким;оценка выражения контракта может даже способствовать окончательному результату вычисления.Несмотря на гибкость языка контрактов, не все желаемые контракты являются выразимыми.Некоторые контракты невыразимы, потому что они могут включать проверку неразрешимых свойств, в то время как другие невыразимы, потому что интерфейс не позволяет достаточно наблюдений.

0 голосов
/ 10 января 2012

Контракт - это концепция работы классов друг с другом.Идея состоит в том, что интерфейс взаимодействия определяет методы, возвращающие тип и имя, но не дает представление о том, как это реализовано.Это делается реализующим классом.

Концепция заключается в том, что когда интерфейс A определяет методы A и B, любой класс, реализующий этот интерфейс, ДОЛЖЕН реализовывать A и B вместе со своими собственными методами.Так что это может работать так:

interface InterfaceA {
    void methodA();
    void methodB(String s);
}

public class ClassA implements InterfaceA {
     public void methodA() { 
         System.out.println("MethodA");
     }

     public void methodB(String s) {
         System.out.println(s);
     }
}

Принцип контракта заключается в том, что все, что реализует интерфейс, должно реализовывать весь интерфейс.Все, что не делает этого, должно быть абстрактным.

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...