Объяснение интерфейсов студентам

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

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

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

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

Ответ 1

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

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

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.

ИЗМЕНИТЬ

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

РЕДАКТИРОВАТЬ 2

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

Ответ 2

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

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

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

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

Ответ 3

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

EDIT:

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

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

дышит

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

Ответ 4

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

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

public interface Plumber
{ //silly code here }

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

public class Rick extends Person implements SoftwareDeveloper, Plumber

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

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

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

Ответ 5

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

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

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

Ответ 6

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

Сегодня мы узнаем лучший способ.

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

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

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

Ответ 7

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

Ответ 8

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

Ответ 9

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

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

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

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

Ответ 10

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

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

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

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

Обновление

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

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

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 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());
  }   
}

Ответ 11

Интерфейсный дизайн описывает это лучше, чем я когда-либо мог 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();
        }
    }
}

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

Список веб-сайтов:

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();
    }
}

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

Список 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 может быть легко преобразован для поддержки на карте, в базе данных или даже в веб-поиске, чтобы удовлетворить растущий масштаб.

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

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

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

  • Пользователь, запрашивающий действие, выполняемое

Ответ 12

Я набрал это как комментарий для ответа 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

Не объясняйте это слишком много, но попробуйте и попросите ученика работать над тем, что может означать синтаксис - возможно, показывая некоторый код, который ссылается на 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, который продает билеты для PassengerTransport. Опираясь на это, вы можете написать полиморфный код, который работает в классах из разных иерархий.

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

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

Вернитесь к первому примеру, чтобы заставить их работать через то, что произойдет, если у SoftwareDeveloper и Plumber есть метод MakeDrink (один делает Cola, другой - Coffee), и мы выполняем MakeDrink на Rick.

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

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

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

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

Ответ 13

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

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

Ответ 14

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

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

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...)

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

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());
       }
    }
}

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

Ответ 15

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

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

Ответ 16

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

Ответ 17

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

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

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

Ответ 18

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

Ответ 19

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

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

Ответ 20

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

Ответ 21

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

Ответ 22

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

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

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

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

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

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

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

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

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

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

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

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

Ответ 23

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

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

Ответ 24

Я бы сказал им: "Интерфейсы определяют, какие варианты поведения предоставляются" и "Реализации обеспечивают такое поведение". Кусок кода, который использует интерфейс, не нуждается в деталях, как все происходит, ему нужно только знать, что может случиться.

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

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

Ответ 25

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

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

Ответ 26

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