Объяснение интерфейсов для студентов [закрыто]


в течение нескольких лет я был ассистентом преподавателя для введения в модуль программирования - Java для студентов первого курса.

в основном все прошло хорошо, и нам удалось довольно хорошо донести объектно-ориентированное программирование до студентов, но одна вещь, которую студенты редко видели, - это интерфейсы.

практически любое объяснение, которое мы дали, либо было слишком надуманным, чтобы быть полезным для обучения, либо слишком далеко от их позиции в качестве новичков. Этот реакция, которую мы имели тенденцию получать, была "я"... смотрите, "переводится как"я не понимаю, и они не звучат полезными".

У кого-нибудь здесь есть способ успешно обучать студентов интерфейсам? Я больше не ассистент преподавателя, но это всегда раздражало меня.

26 60

26 ответов:

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

например, скажем, мы собираемся нарисовать некоторые объекты:

public class Painter {
    private List<Paintable> paintableObjects;

    public Painter(){
       paintableObjects = new ArrayList<Paintable>();
    }

    public void paintAllObjects(){
        for(Paintable paintable : paintableObjects){
            paintable.paint();
        }
    }
}

public interface Paintable {
     public void paint();
}

теперь вы можете объяснить студентам, что без интерфейса Paintable объект Painter должен иметь методы для рисования определенных типов объектов, таких как метод под названием paintFences() и paintRocks() и нам нужно будет иметь новый Collection для каждый тип объектов мы хотим, чтобы художник мог рисовать.

но, к счастью, у нас есть интерфейсы, которые делают объекты рисования ветер и как объекты окрашены остается полностью до классов, которые реализуют интерфейс Paintable.

EDIT

еще одно преимущество, которое я забыл упомянуть, заключается в том, что если вам когда-либо понадобится добавить новый объект для рисования в свою базу кода, все, что вам нужно сделать, это создать новый класс, который реализует Paintable и Класс художника никогда не должен меняться. В этом смысле класс художников никогда не зависит от объектов, которые он собирается рисовать, ему нужно только уметь их рисовать.

EDIT 2

James Raybould напомнил мне о ключевом использовании интерфейсов, о которых я забыл упомянуть: наличие интерфейса между вашими компонентами, такими как объекты Paintable и объекты Painter, позволяет вам легче развиваться с другими людьми. Один разработчик может работать над объектами Painter и другой может работать с объектами Paintable, и все, что им нужно сделать, чтобы правильно функционировать вместе, - это заранее определить общий интерфейс, который они оба будут использовать. Я знаю, когда я работал над проектами с другими людьми в проектах уровня колледжа, это действительно полезно, когда вы пытаетесь заставить всех работать над разными частями проекта и все еще иметь все компоненты, которые хорошо сочетаются в конце.

при объяснении интерфейсов и объектно-ориентированных концепций в целом для не-программистов я всегда использую аналогию с домашней развлекательной системой.

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

видео в разъеме телевизора-это интерфейс, который реализован DVD-плеер и кабельная коробка, а также ряд других типов устройств.

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

" там, где классы-это что-то, обычно интерфейсы что-то делают. Так что у меня может быть машина, но я никогда не буду "тащить", но я могу пойти за рулем... так что мой автомобиль может реализовать" управляемый " интерфейс."

EDIT:

Марк поднимает хороший вопрос. Интерфейсы вообще ничего не делают, а вместо этого определяют, какое поведение происходит. И он также поднимает хороший вопрос о том, чтобы не путать аудиторию. Не то, чтобы это нормально, чтобы запутать опытных разработчиков, но это определенно не очень хорошая идея, чтобы запутать совершенно нового студента. В свете этого, я пересматриваю свою команду в много-вкладыш.

", где классы определяют существование, интерфейсы определяют поведение. Классы определяют, что что-то есть, в то время как интерфейсы определяют, что что-то делает. Поэтому у меня может быть автомобиль, и у него есть такие вещи, как двигатель, сколько у него газа, что это исторический MPG и т. д., Но я никогда не буду "тащить". С другой стороны, я мог бы сесть за руль... может ли моя машина ездить? Оно может если я дам ему метод привода. Я также могу иметь "управляемый" интерфейс с методом привода и оставить его до автомобиля, чтобы определить, что на самом деле означает вождение. Теперь, если у меня есть только автомобили, это не так уж и важно, чтобы иметь интерфейс. Но как насчет грузовиков? Если они оба управляемы, я могу просто иметь List<Drivable для них обоих. Конечно, наблюдательный студент говорит: "Почему автомобиль и грузовик не могут просто расширить транспортное средство с помощью абстрактного метода привода?- Что, на самом деле, весьма обоснованно. Но, как насчет космический челнок? Очень немногие из компонентов между автомобилем и грузовиком применяются к космическому челноку, поэтому он не кажется хорошо подходящим для расширения класса транспортного средства. Или как насчет будущих автомобилей? Мы понятия не имеем, на что они могут быть похожи, у них может не быть chassises, они могут быть просто пузырьками энергии, которые перемещают нас, но мы все равно можем назвать их поведение drive()."

дышит

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

Ну, я только что объяснил интерфейсы партнеру по работе, она изучала java от прогресса, и она действительно не получила все вещи ООП в начале, поэтому я просто объяснил все с точки зрения не программной инженерии, мое объяснение интерфейсов, где что-то вроде этого:

Предположим, вы хотите нанять сантехника, чтобы исправить некоторые вещи в вашем доме, вы не знаете (и вам все равно), кого вы можете нанять, но вы знаете, что сантехник должен быть в состоянии сделать. Таким образом, вы определяете набор задач, которые любой, кто утверждает, что сантехник должен знать, как это сделать. Конечно, каждый может иметь свой собственный способ выполнения каждой задачи, но, в конце концов, человек, которого вы нанимаете-это сантехник, потому что они знают, как сделать каждую задачу. Итак, если бы вы написали это на java, первое, что нужно сделать, это определить interface водопроводчик вот так:

public interface Plumber
{ //silly code here }

хорошо, тогда предположим, что я знаю, как выполнять каждую задачу, которую вы запрашиваете, и поэтому я полностью совместим с ваши требования и так согласно вам я водопроводчик. Итак, сегодня я решаю быть вашим сантехником, и вы решаете нанять меня (yay!), основываясь на последнем примере, вы можете сказать, что я человек, который знает, как разрабатывать программное обеспечение и сантехнику определенным образом, если бы я написал код для меня как класс, я мог бы написать что-то вроде этого:

public class Rick extends Person implements SoftwareDeveloper, Plumber

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

Plumber thePlumber = rick;
thePlumber.fixLeak(myHouse.bathroom.leak) // =(

С этого момента, остальные ООП концепции были легко объяснимы.

ну, недавно мне довелось объяснить это кому-то близкому. То, как я объяснил вопрос " почему интерфейсы?", является примером USB-порта и USB-накопителей.

USB-порт можно рассматривать как спецификацию, и любой USB-накопитель может вписаться в него, если они реализуют спецификацию. Таким образом, в этом случае порт становится интерфейсом, а многочисленные типы USB-накопителей становятся классом. Проведение этого примера вперед, если бы я должен был предоставить кто-то USB-накопитель (класс), мне не нужно было бы говорить им (вызывающий метод) о том, что я передаю. Если бы вызывающий метод взял USB-накопитель (тип класса) в качестве ссылки, я бы не смог передать любой, но только USB-накопитель, для которого предназначен порт.

чтобы подвести итог, Intefaces, помогите вызывающему объекту быть comptabile с вызывающим методом (в случае использования, когда вызывающий метод ожидает экземпляр определенного типа), независимо от того, какой экземпляр вы передаете, вызывающий абонент, а также вызываемый абонент уверены, что он (экземпляр) будет вписываться в ссылку на интерфейс (USB-порт для аналогии).

класс, мы провели последние несколько сеансов реализации quicksort. Было трудно отсортировать этот список людей по именам. Что бы вы сейчас делали, если бы вам пришлось сортировать этот список по классам? И что бы вы сделали, если бы вам пришлось сортировать список dinousaurs по возрасту? Единственный способ, который вы знаете до сих пор, - это скопировать код quicksort и изменить сравнение и типы, с которыми он работает. Это будет работать-пока вы не найдете ту неуловимую ошибку, которая всегда мучила вашу quicksort, и ее нужно было исправить в нескольких десятков экземпляров, что быстрая сортировка разбросанных по всей место.

сегодня мы будем учиться лучше.

мы можем написать quicksort без определения порядка, в который мы хотим отсортировать список, и определить этот порядок (и только этот порядок) отдельно, когда мы вызываем эту quicksort.

[вставить объяснение механики интерфейсов и полиморфизма, используя интерфейс компаратора в качестве примера, здесь]

теперь, есть только одна копия quicksort, и ошибки должны быть исправлены только один раз. Кроме того, люди могут использовать quicksort, не понимая его (или если они его поняли, не думая о его механике, когда вы хотите что-то сортировать). Кроме того, людям, пишущим quicksort, не нужно было знать порядок, в котором вам нужно отсортировать свой список. Таким образом, интерфейс изолировал две группы программистов, позволяя им разрабатывать свои части программного обеспечения в изоляции. Вот почему, во многих языках программирования, вы найдете хорошо реализованы и протестированы методы сортировки в api, хотя программисты этих методов не могли знать все типы объектов и порядков, которые люди хотят сортировать позже.

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

Я рекомендую первую главу Head First Design Patternдля этого. Моделирование утки объясняет проблему с использованием наследования, и остальная часть главы продолжает объяснять, как это сделать.

Это объясняет лучше всего: (ссылка из этого учебник)

в программной инженерии существует ряд ситуаций, когда разрозненным группам программистов важно договориться о "контракте", который определяет, как их программное обеспечение взаимодействует. Каждая группа должна иметь возможность писать свой код без каких-либо знаний о том, как написан код другой группы. Вообще говоря, интерфейсы-это такие контракты. Например, представьте себе футуристическое общество, где управляемые компьютером роботизированные автомобили перевозят пассажиров по улицам города без участия человека-оператора. Автопроизводители пишут программное обеспечение (Java, конечно), которое управляет автомобилем-стоп, старт, ускорение, поворот налево и так далее. Другая промышленная группа, изготовители электронных приборов наведения, делает компьютерные системы которые получают данные по положения GPS (глобальной системы позиционирования) и беспроволочную передачу условий движения и используют ту информацию для того чтобы управлять автомобиль.

автопроизводители должны опубликовать стандартный отраслевой интерфейс, который подробно описывает, какие методы могут быть вызваны, чтобы заставить автомобиль двигаться (любой автомобиль, от любого производителя). Изготовители руководства могут тогда написать программное обеспечение, которое вызывает методы, описанные в интерфейсе, чтобы управлять автомобилем. Ни одна промышленная группа не должна знать, как реализуется программное обеспечение другой группы. Фактически, каждая группа считает свое программное обеспечение высоко проприетарным и оставляет за собой право измените его в любое время, пока он продолжает придерживаться опубликованного интерфейса.

дополнительная Ссылка:http://download-llnw.oracle.com/javase/tutorial/java/concepts/interface.html

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

выбор между интерфейсом и базовым классом является дизайнерское решение. Я бы держал это просто.

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

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

обновление

вот простая программа, которую вы можете использовать, чтобы продемонстрировать, насколько похожи наследование и интерфейсы. Измените программу, чтобы сделать базовым интерфейс вместо класса. В ClassA заменить "extends" на "implements". Результат программы будет таким же.

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

abstract class Base {
  public void behavior() {};
};

class ClassA extends Base {
  public void behavior() {
    System.out.println("ClassA implementation of Base behavior");
  }
};

class ClassB {
  public void behavior() {
    System.out.println("ClassB's version of behavior");    
  }
}

public class InterfaceExample {

  public void processBase (Base i) {
    i.behavior();
  }

  public static void main (String args[]) {
      InterfaceExample example = new InterfaceExample();
      example.processBase(new ClassA());
  }   
}

Интерфейс Ориентированный Дизайн описывает это лучше, чем я когда-либо мог http://pragprog.com/titles/kpiod/interface-oriented-design. автор использует некоторые отличные примеры интерфейсов против наследования для таких вещей, как таксономия животного царства. Он имеет некоторые из лучших аргументов против чрезмерного наследования и разумного использования интерфейсов, которые я читал на сегодняшний день.

куча сайтов с несовместимыми способами привлечения их вверх:

список Facebook.java:

public class Facebook {
    public void showFacebook() {
        // ...
    }
}

список YouTube.java:

public class YouTube {
    public void showYouTube() {
        // ...
    }
}

список StackOverflow.java:

public class StackOverflow {
    public void showStackOverflow() {
        // ...
    }
}

клиент вручную обрабатывает различные методы, которые используют веб-сайты, чтобы принести себя:

список ClientWithoutInterface.java:

public class ClientWithoutInterface {
    public static void main(String... args) {
        String websiteRequested = args[0];
        if ("facebook".equals(websiteRequested)) {
            new Facebook().showFacebook();
        } else if ("youtube".equals(websiteRequested)) {
            new YouTube().showYouTube();
        } else if ("stackoverflow".equals(websiteRequested)) {
            new StackOverflow().showStackOverflow();
        }
    }
}

ввести интерфейс веб-сайта, чтобы сделать работу клиента проще:

список сайт.java:

public interface Website {
    void showWebsite();
}

список Facebook.java:

public class Facebook implements Website {
    public void showWebsite() {
        // ...
    }
}

список YouTube.java:

public class YouTube implements Website {
    public void showWebsite() {
        // ...
    }
}

список StackOverflow.java:

public class StackOverflow implements Website {
    public void showWebsite() {
        // ...
    }
}

список ClientWithInterface.java:

public class ClientWithInterface {
    public static void main(String... args) {
        String websiteRequested = args[0];
        Website website;
        if ("facebook".equals(websiteRequested)) {
            website = new Facebook();
        } else if ("youtube".equals(websiteRequested)) {
            website = new YouTube();
        } else if ("stackoverflow".equals(websiteRequested)) {
            website = new StackOverflow();
        }
        website.showWebsite();
    }
}

возглас-де-ду, больше ничего? На самом деле мы можем пойти немного дальше и есть клиент веревка пару друзей, чтобы помочь ему найти и сделать запрошенный сайт:

список ClientWithALittleHelpFromFriends.java:

public class ClientWithALittleHelpFromFriends {
    public static void main(String... args) {
        WebsiteFinder finder = new WebsiteFinder();
        WebsiteRenderer renderer = new WebsiteRenderer();
        renderer.render(finder.findWebsite(args[0]));
    }
}

список WebsiteFinder.java:

public class WebsiteFinder {
    public Website findWebsite(String websiteRequested) {
        if ("facebook".equals(websiteRequested)) {
            return new Facebook();
        } else if ("youtube".equals(websiteRequested)) {
            return new YouTube();
        } else if ("stackoverflow".equals(websiteRequested)) {
            return new StackOverflow();
        }
    }
}

список WebsiteRenderer.java:

public class WebsiteRenderer {
    public void render(Website website) {
        website.showWebsite();
    }
}

оглядываясь на ClientWithoutInterface, он полностью связан как с конкретным поиском, так и с рендерингом. Было бы очень сложно управлять, когда вы попадаете на сотни или тысячи сайтов. С помощью сайт интерфейс на месте WebsiteFinder может быть легко преобразован для резервного копирования на карте, базе данных или даже веб-поиска, чтобы удовлетворить растущий масштаб.

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

  • текущая нагрузка на машину

  • размер набора данных (алгоритмы сортировки могут быть выбраны)

  • пользователь запрашивает выполнение действия

Я набирал это как комментарий к ответу Harima555s, но он расширился. Я задавался вопросом, Имеет ли смысл начинать с другого конца - дать им почувствовать, как полезны интерфейсы, прежде чем переходить к тому, как вы их пишете.

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

далее представим пример классов с интерфейсы, чтобы преодолеть концепцию ролей / контрактов. Чтобы упростить ситуацию, начните с одного суперкласса.

public class Rick extends Person implements SoftwareDeveloper, Plumber
public class Zoe  extends Person implements SoftwareDeveloper, Chef
public class Paul extends Person implements Plumber, Chef
public class Lisa extends Person implements Plumber

не объясняйте это слишком много, но попробуйте заставить студента работать через то, что синтаксис может означать - возможно, показывая некоторый код, который ссылается на водопроводчика или SoftwareDeveloper.

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

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

public class Plane extends Vehicle implements Fly, PassengerTransport, Serviceable
public class Train extends Vehicle implements PassengerTransport, Serviceable
public class Bird  extends Animal  implements Fly

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

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

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

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

вернитесь к первому примеру, заставьте их работать над тем, что произойдет, если у SoftwareDeveloper и Plumber есть метод "MakeDrink" (один делает Колу, другой делает кофе), и мы выполняем MakeDrink на Рике.

попробуйте подтолкнуть кого-то к рассмотрению идеи о том, что если MakeDrink остается абстрактным в обоих "суперклассах", проблема уходит. На этом этапе, получив концептуальную сторону, мы должны быть готовы рассмотреть синтаксис для определения интерфейса.

(Я рассматривал введение второй причины-трудности написания общего кода, который может быть применен к различным иерархиям классов, но обнаружил, что вы в конечном итоге получаете "ну почему вы не можете наследовать атрибут высоты от интерфейса" или слишком рано обсуждать общее Программирование).

Я думаю, что к настоящему времени мы должны были рассмотреть концепции с помощью примеров Микки Мауса - и вы могли бы вернуться к объяснению правильного техническая терминология и использование реальных примеров из Java API.

  • я бы не хотел путать людей, когда они пытаются изучать Java/интерфейсы, но как только они это получат, возможно, стоит отметить, что другие языки OO используют разные подходы к одной и той же проблеме, от множественного наследования до утиного ввода-и если они заинтересованы, они должны исследовать их.

вы также преподаете JDBC? Возьмите это в качестве примера. Это отличный реальный пример того, насколько мощные интерфейсы. В JDBC вы пишете код против API, которые существуют почти только интерфейсы. Драйвер JDBC-это конкретная реализация. Вы можете легко повторно использовать код JDBC на многих БД без перезаписи кода. Вам просто нужно переключить файл jar реализации драйвера JDBC и имя класса драйвера, чтобы заставить его работать на другой БД.

по крайней мере, с помощью интерфейсов предлагает вам возможность перейти от конкретной реализации (логика кода, которая отвечает за поведение) в какой-то момент без переписывания всего кода. Попробуйте использовать примеры из реального мира при объяснении вещей. Было бы больше смысла.

Ну, я нашел в последнее время очень полезный способ использования интерфейса.

у нас есть много объектов...

public class Settings { String[] keys; int values; }
public class Car { Engine engine; int value; }
public class Surface { int power; int elseInt; }
// and maaany more (dozens...)

теперь, кто-то создает (т. е.) стол и хочу показать некоторые объекты из списка всех объектов, а объекты в списке он должен написать метод, который возвращает string[].

String[] toArrayString()

поэтому он просто реализует этот метод во всех классах, которые ему нужны в таблице

public class Settings { String[] keys; int values; public String[] toArrayString {...} }
public class Car { Engine engine; int value; } // THIS NOT
public class Surface { int power; int elseInt; public String[] toArrayString {...} }
// and maaany more (dozens...)

теперь, когда он создает таблицу, он пишет что-то вроде это

public void createTable() {
    for(Object obj : allObjects) {
       if(obj instanceof Settings) {
          Settings settings = (Settings)obj;
          table.add(settings.toArrayString());
       }
       if(obj instanceof Surface) {
          // cast...
       }
       // etc multiple times...
    }
}

С интерфейсом этот код может быть значительно короче и легче читать и поддерживать:

public interface ISimpleInterface { String[] toArrayString; }

public class Settings implements ISimpleInterface { String[] keys; int values; public String[] toArrayString {...} }
public class Car { Engine engine; int value; } // THIS NOT
public class Surface implements ISimpleInterface { int power; int elseInt; public String[] toArrayString {...} }

public void createTable() {
    for(Object obj : allObjects) {
       if(obj instanceof ISimpleInterface) {
          ISimpleInterface simple = (ISimpleInterface)obj;
          table.add(simple.toArrayString());
       }
    }
}

кроме того, мы можем реализовать несколько интерфейсов очень чистым и эффективным способом без какого-либо вывода (вывод иногда невозможен, а не только в том случае, когда класс уже использует какой-то другой вывод).

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

в этом вопросе есть несколько хороших сценариев, которые объясняют, почему за использование интерфейсов.

Вопрос Переполнения Стека

реальной стоимости интерфейсов поставляется с будучи в состоянии переопределить компонентов в 3-й партии API-интерфейсы и механизмы. Я бы построил задание, где учащимся нужно переопределить функциональность в предварительно построенной библиотеке, которую они не могут изменить (и не имеют источника).

чтобы быть более конкретным, скажем, у вас есть" фреймворк", который генерирует HTML-страницу, реализованную как класс страницы. И Пейдж.рендер (поток) генерирует html. Предположим, что страница принимает экземпляр загерметизированная класс ButtonTemplate. Объект ButtonTemplate имеет свой собственный метод рендеринга, так что на странице.рендер (поток) buttonTemplate.render (label,stream) вызывается в любом месте, где есть кнопка, и он создает html для кнопки отправки. В качестве примера для студентов, скажем, что мы хотим заменить эти кнопки Подтвердить ссылками.

Я бы не дал им большого направления, кроме описания конечного результата. Они должны будут бить их головы, пытаясь различные решения. " должны ли мы попытаться разобрать теги кнопок и заменить их тегами привязки? Можем ли мы подкласс ButtonTemplate делать то, что мы хотим? О, подожди. Он запечатан! О чем они думали, когда запечатывали этот класс!?!" затем после этого назначения покажите вторую структуру с интерфейсом ILabeledTemplate с методом render(label,stream).

в дополнение к другим ответам, вы можете попробовать объяснить это с другой точки зрения. Студенты, я уверен, уже знают о наследовании, потому что он застрял в горле каждого студента Java из, вероятно, лекции один. Они слышали о множественном наследовании? Разрешение метода рассматривалось как проблема проектирования в C++ (а также в Perl и других языках множественного наследования), потому что концептуально неясно, что именно должно произойти, когда метод вызывается в a подкласс, который определен в двух его базовых классах. Оба казнены? Какой из них идет первым? Можно ли на него ссылаться конкретно? Смотрите также раздел проблема. Я понимаю, что эта путаница была решена просто путем введения интерфейсов, которые не имеют реализации, поэтому нет никакой двусмысленности в отношении того, какую реализацию использовать во время разрешения метода.

Если класс необходимо обрабатывать точно один часть абстрактной функциональности, и Не нужно было наследовать какой-либо другой класс, можно использовать абстрактный класс для представления функциональности, а затем извлечь урок из этого. Обратите внимание на два пункта, выделенные курсивом. Интерфейсы позволяют классу вести себя как несколько независимых типов абстрактных вещей, даже если класс является производным от другого класса, который не ведет себя как эти типы вещей. Таким образом, интерфейсы удовлетворяют одному из основных случаев использования для множественного наследования, без мерзости, которая идет вместе с множественным наследованием.

простой реальный пример очень практичного интерфейса: iEnumerable. Если класс содержит некоторое произвольное число некоторого типа элемента, очень полезно, чтобы другой класс действовал на все эти элементы, не беспокоясь о деталях объекта, который их содержит. Если бы "enumerableThing" был абстрактным классом, это было бы невозможно, чтобы объект любого класса, производный от чего-то, что не было "enumerableThing", передавался в код, который ожидал enumerableThing. Поскольку любой класс, включая производные классы, может реализовать enumerableThing без учета того, делают ли это базовые классы, можно добавить способность перечисления к любому классу.

давным-давно я прочитал книгу (не могу вспомнить ее название), и у нее была довольно хорошая аналогия для интерфейсов. Если вы (или ваши студенты) когда-либо ходили в магазин мороженого Cold Stone Creamery, это будет звучать знакомо. Холодный камень имеет мороженое, и с мороженым вы можете добавить несколько разных вещей в мороженое (так называемые миксы в холодном камне). Эти миксы будут аналогичны интерфейсам. Ваш класс (или мороженое) может иметь столько интерфейсов (или миксов), сколько вы хотеть. Добавление интерфейса (или тщательно перемешать) добавить содержание (или вкус) того, что интерфейс (или смесь-в) в вашем классе (или мороженое). Надеюсь, это поможет!

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

во-первых, студенты должны усвоить понятие абстракции. Когда вы (вы == ученики) видите учителя, вы можете описать его как учителя... Вы также можете описать его как сотрудника (школы). И вы можете описать его как человека. Вы будете три раза. Это" титулы", которые вы можете ему дать.

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

(нарисуйте все это на доске в виде UML).

и это архитектура, которая будет описывать (грубо) положение учителя науки в обществе.

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

в программировании, интерфейс-это уровень абстракции. Он описывает действия, которые может выполнить группа объектов. Каждый объект имеет уникальный способ выполнения действия, но тип действия один и тот же.

Возьмите несколько музыкальных инструментов, например фортепиано, гитара и флейта. В чем они заключаются общее ? Музыкант может играть на них. Вы не можете попросить музыканта дуть в 3 инструмента, но вы можете попросить его играть на них.

архитектура всей концепции будет следующей:

интерфейс (что у них общего) - это инструмент. Потому что они все инструменты : это абстракция, которую они все имеют в общем. Что они могут сделать вместе ? Играть. Таким образом, вы определяете абстрактный метод, называемый Play.

вы не можете определить, как "инструмент" будет играть, потому что это зависит от типа документа. Флейта является одним из видов инструмента. Так класс флейта реализует инструмент. Теперь вы должны определить, что музыкант будет делать, когда он играет на этом типе инструмента. Таким образом, вы определяете метод воспроизведения. Это определение будет переопределять определение инструмента. Сделайте то же самое с 2 другими инструментами.

теперь, если у вас есть список инструментов, но вы не знаете, какой они тип, вы все равно можете "попросить" их играть. Каждая флейта будет взорван. Каждая гитара будет поцарапана. Каждый пианино будет ... ха!... на пианино ? все равно !

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

вы также можете сравнить и сравнить интерфейсы в Java С C++ (где вы в конечном итоге используете несколько классов наследования и/или "друзей").

(по крайней мере, для меня, это показало мне, насколько проще/проще интерфейсы были в Java :-)

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

хорошим примером является шаблон DAO. Он определяет поведение как "сохранить", "загрузить", "удалить". У вас может быть реализация, которая работает с БД, и реализация, которая переходит в файловую систему.

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

Я думаю, что в целом, практическое обучение всегда помогает укрепить концепции после лекций и примеров. Поэтому в том же духе, что и Меритон, я бы представил две версии одной и той же программы. (quicksort является хорошим примером)

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

Я всегда думаю об этом как о средстве (вербально) общаться как можно меньше, потому что это (хорошая связь) является самой сложной вещью в программной инженерии. То же самое для веб-сервисов и SOA. Если вы даете кому-то интерфейс и говорите: "пожалуйста, предоставьте мне эту услугу."это очень удобный способ, потому что вам не нужно много объяснять, и компилятор проверит, правильно ли они сделали работу, а не вы! (Я имею в виду, не совсем, но по крайней мере это будет гарантировать эти методы есть).