Почему я не могу понять интерфейсы?

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

Я говорю о интерфейсах в контексте интерфейсов и абстрактных classов.

Интерфейсы позволяют вам программировать вместо «описания» вместо типа, что позволяет вам более свободно связывать элементы вашего программного обеспечения.

Подумайте об этом так: вы хотите поделиться данными с кем-то в кубе рядом с вами, поэтому вы вытаскиваете свою флешку и копируете / вставляете. Вы идете по соседству, и парень говорит: «Это USB?» и вы говорите «да» – все готово. Не имеет значения размер флеш-накопителя, а также производитель – все, что имеет значение, – это USB.

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

public void Paint(Car car, System.Drawing.Color color)... 

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

 public void Paint (Vehicle vehicle, System.Drawing.Color color)... 

это расширит ваше приложение … пока ваш клиент не сказал: «Теперь я хочу рисовать дома!» То, что вы могли бы сделать с самого начала, создало интерфейс:

 public interface IPaintable{ void Paint(System.Drawing.Color color); } 

… и передал это вашей рутине:

 public void Paint(IPaintable item, System.Drawing.Color color){ item.Paint(color); } 

Надеюсь, это имеет смысл – это довольно упрощенное объяснение, но, надеюсь, доходит до сути.

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

Скажем, у вас есть несколько classов под названием Dog, Cat и Mouse. Каждый из этих classов является Pet, и в теории вы могли бы наследовать их всех из другого classа под названием Pet, но вот проблема. Домашние животные сами по себе ничего не делают. Вы не можете пойти в магазин и купить домашнее животное. Вы можете пойти и купить собаку или кошку, но домашнее животное – абстрактное понятие, а не конкретное.

Значит, вы знаете, что домашние животные могут делать определенные вещи. Они могут спать или есть, и т. Д. Итак, вы определяете интерфейс под названием IPet, и он выглядит примерно так (синтаксис C #),

 public interface IPet { void Eat(object food); void Sleep(int duration); } 

Каждый из ваших classов Dog, Cat и Mouse реализует IPet.

 public class Dog : IPet 

Итак, теперь каждый из этих classов должен иметь свою собственную реализацию «Ешь и Сон». У тебя есть контракт … Теперь в чем смысл.

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

 public class PetStore { public static IPet GetRandomPet() { //Code to return a random Dog, Cat, or Mouse } } IPet myNewRandomPet = PetStore.GetRandomPet(); myNewRandomPet.Sleep(10); 

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

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

Самый простой ответ заключается в том, что интерфейсы определяют то, что может сделать ваш class. Это «контракт», в котором говорится, что ваш class сможет выполнить это действие.

 Public Interface IRollOver Sub RollOver() End Interface Public Class Dog Implements IRollOver Public Sub RollOver() Implements IRollOver.RollOver Console.WriteLine("Rolling Over!") End Sub End Class Public Sub Main() Dim d as New Dog() Dim ro as IRollOver = TryCast(d, IRollOver) If ro isNot Nothing Then ro.RollOver() End If End Sub 

В принципе, вы гарантируете, что class Dog всегда имеет возможность опрокидываться до тех пор, пока он продолжает реализовывать этот интерфейс. Если кошки когда-либо получат возможность RollOver (), они тоже могут реализовать этот интерфейс, и вы можете относиться к ним как к Собакам, так и кошкам однородно, задавая им RollOver ().

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

Интерфейсы – это механизм для уменьшения связи между различными, возможно, разрозненными частями системы.

С точки зрения .NET

  • Определение интерфейса – это список операций и / или свойств.
  • Методы интерфейса всегда общедоступны.
  • Сам интерфейс не обязательно должен быть общедоступным.

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

Кроме того .net имеет только одно наследование, а интерфейсы – необходимость для объекта подвергать методы другим объектам, которые не знают или лежат вне иерархии classов. Это также известно как раскрытие поведения.

Пример, который немного более конкретный:

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

 // first pass - not maintainable void SubmitToWorkflow(object o, User u) { if( o is StreetMap ) { var map = (StreetMap)o; map.LastUpdated = DateTime.UtcNow; map.UpdatedByUser = u.UserID; } else if( o is Person ) { var person = (Person)o; person.LastUpdated = DateTime.Now; // whoops .. should be UtcNow person.UpdatedByUser = u.UserID; } // whoa - very unmaintainable. 

В приведенном выше коде SubmitToWorkflow() должен знать о каждом объекте. Кроме того, код беспорядок с одним массивным if / else / switch, нарушает принцип Do not Repeat Yourself (DRY) и требует от разработчиков запоминать изменения копирования / вставки при каждом добавлении нового объекта в систему.

 // second pass - brittle void SubmitToWorkflow(object o, User u) { if( o is DTOBase ) { DTOBase dto = (DTOBase)o; dto.LastUpdated = DateTime.UtcNow; dto.UpdatedByUser = u.UserID; } 

Чуть лучше, но все же хрупкий. Если мы хотим представить другие типы объектов, нам все равно нужно больше аргументов case. и т.п.

 // third pass pass - also brittle void SubmitToWorkflow(DTOBase dto, User u) { dto.LastUpdated = DateTime.UtcNow; dto.UpdatedByUser = u.UserID; 

Все еще хрупкие, и оба метода налагают ограничение, что все DTO должны реализовать это свойство, которое мы указали, не было универсально применимым. У некоторых разработчиков может возникнуть соблазн написать методы do-nothing, но это плохо пахнет. Мы не хотим, чтобы classы притворялись, что поддерживают отслеживание обновлений, но не делают этого.

Интерфейсы, как они могут помочь?

Если мы определим очень простой интерфейс:

 public interface IUpdateTracked { DateTime LastUpdated { get; set; } int UpdatedByUser { get; set; } } 

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

 public class SomeDTO : IUpdateTracked { // IUpdateTracked implementation as well as other methods for SomeDTO } 

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

 void SubmitToWorkflow(object o, User u) { IUpdateTracked updateTracked = o as IUpdateTracked; if( updateTracked != null ) { updateTracked.LastUpdated = DateTime.UtcNow; updateTracked.UpdatedByUser = u.UserID; } // ... 
  • Мы можем отметить, что изменение void SubmitToWorkflow(IUpdateTracked updateTracked, User u) гарантирует безопасность типа, однако в этих обстоятельствах оно не кажется соответствующим.

В некотором производственном коде, который мы используем, у нас есть генерация кода для создания этих classов DTO из определения базы данных. Единственное, что делает разработчик, – это правильно создать имя поля и украсить class интерфейсом. Пока свойства называются LastUpdated и UpdateByUser, он просто работает.

Возможно, вы спрашиваете, что произойдет, если моя firebase database устарела, и это невозможно? Вам просто нужно немного набрать текст; еще одна замечательная особенность интерфейсов – они могут позволить вам создать мост между classами.

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

 // using an interface to bridge properties public class LegacyDTO : IUpdateTracked { public int LegacyUserID { get; set; } public DateTime LastSaved { get; set; } public int UpdatedByUser { get { return LegacyUserID; } set { LegacyUserID = value; } } public DateTime LastUpdated { get { return LastSaved; } set { LastSaved = value; } } } 

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

 // explicit implementation of an interface public class YetAnotherObject : IUpdatable { int IUpdatable.UpdatedByUser { ... } DateTime IUpdatable.LastUpdated { ... } 

Наличие такой гибкости, чтобы определить, как class реализует интерфейс, дает разработчику большую свободу отделять объект от методов, которые его потребляют. Интерфейсы – отличный способ разбить сцепление.

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

Как я уже упоминал ранее, и другими респондентами, вы можете создавать методы, которые берут и / или возвращают ссылки на интерфейс, а не конкретную ссылку на class. Если мне нужно найти дубликаты в списке, я мог бы написать метод, который принимает и возвращает IList (интерфейс, определяющий операции, которые работают над списками), и я не ограничен конкретным classом коллекции.

 // decouples the caller and the code as both // operate only on IList, and are free to swap // out the concrete collection. public IList FindDuplicates( IList list ) { var duplicates = new List() // TODO - write some code to detect duplicate items return duplicates; } 

Предотrotation версий

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

См. Этот пост в Haacked для хорошего обсуждения.

Интерфейсы против абстрактных (базовых) classов

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

Стоит повторить, что в .net class может наследовать только один class, но class может реализовать столько интерфейсов, сколько ему нравится.

Внедрение зависимости

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

 class AnnualRaiseAdjuster : ISalaryAdjuster { AnnualRaiseAdjuster(IPayGradeDetermination payGradeDetermination) { ... } void AdjustSalary(Staff s) { var payGrade = payGradeDetermination.Determine(s); s.Salary = s.Salary * 1.01 + payGrade.Bonus; } } 

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

Это не DI-праймер, хотя есть целые книги, посвященные этому предмету; приведенный выше пример очень упрощен.

Это довольно длинный предмет, но позвольте мне попытаться сделать это простым.

Интерфейс – это «они называют это» – Контракт. Но забудь об этом слове.

Лучший способ понять их – это какой-то пример псевдокода. Вот так я их давно понял.

Предположим, у вас есть приложение, которое обрабатывает сообщения. Сообщение содержит некоторые вещи, как тему, текст и т. Д.

Поэтому вы пишете MessageController для чтения базы данных и извлечения сообщений. Очень приятно, пока вы вдруг не услышите, что Faxes также будут реализованы в ближайшее время. Итак, теперь вам нужно будет прочитать «Факсы» и обработать их как сообщения!

Это может легко превратиться в код Spagetti. Итак, что вы делаете вместо того, чтобы иметь MessageController, чем управляет только «Сообщениями», вы можете работать с интерфейсом IMessage (я просто обычное использование, но не обязательно).

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

Поэтому, когда вы создаете classы EMail, Fax, PhoneCall, вы создаете их. Внедрите интерфейс IMessage .

Поэтому в вашем MessageController вы можете вызвать такой метод:

 private void ProcessMessage(IMessage oneMessage) { DoSomething(); } 

Если вы не использовали интерфейсы, вам нужно было бы:

 private void ProcessEmail(Email someEmail); private void ProcessFax(Fax someFax); etc. 

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

Почему и как ?

Поскольку интерфейс – это контракт, который указывает некоторые вещи, которые вы должны придерживаться (или реализовать), чтобы иметь возможность использовать его. Думайте об этом как о значке . Если ваш объект «Факс» не имеет интерфейса IMessage, то ваш метод ProcessMessage не сможет с ним работать, он выдаст вам недопустимый тип, поскольку вы передаете факс методу, который ожидает сообщения IMessage объект.

Вы видите смысл?

Подумайте о интерфейсе как о «подмножестве» методов и свойств, которые у вас будут доступны, несмотря на реальный тип объекта. Если исходный объект (факс, электронная почта, PhoneCall и т. Д.) Реализует этот интерфейс, вы можете безопасно передать его через методы, которым нужен этот интерфейс.

Там больше волшебства, вы можете CAST интерфейсы вернуться к своим оригинальным объектам:

Факс myFax = (Факс) SomeIMessageThatIReceive;

У ArrayList () в .NET 1.1 был хороший интерфейс под названием IList. Если у вас есть IList (очень «общий»), вы можете преобразовать его в ArrayList:

 ArrayList ar = (ArrayList)SomeIList; 

И есть тысячи образцов там в дикой природе.

Интерфейсы, такие как ISortable, IComparable и т. Д., Определяют методы и свойства, которые вы должны реализовать в своем classе для достижения этой функциональности.

Чтобы расширить наш образец, вы можете иметь Список <> писем, факсов, PhoneCall, все в одном и том же списке, если Тип является IMessage, но вы не могли бы объединить их все, если бы объекты были просто Email, Факс и т. Д. ,

Если вы хотите отсортировать (или перечислить, например) свои объекты, вам понадобится их реализовать соответствующий интерфейс. В примере .NET, если у вас есть список объектов «Факс» и вы хотите отсортировать их с помощью MyList.Sort (), вам необходимо сделать свой class факса следующим образом:

 public class Fax : ISorteable { //implement the ISorteable stuff here. } 

Надеюсь, это даст вам подсказку. Другие пользователи могут опубликовать другие хорошие примеры. Удачи! и Объявите силу INterfaces.

предупреждение : не все хорошо о интерфейсах, есть некоторые проблемы с ними, пуристы ООП начнут войну с этим. Я останусь в стороне. Один из недостатков Interfce (по крайней мере, в .NET 2.0) заключается в том, что вы не можете иметь членов PRIVATE или защищены, он должен быть общедоступным. Это имеет смысл, но иногда вы хотите, чтобы вы просто объявляли вещи частными или защищенными.

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

Кодовая база с хорошо продуманными интерфейсами становится намного легче обсуждать. «Да, вам нужен CredentialsManager для регистрации новых удаленных серверов». «Передайте PropertyMap в ThingFactory, чтобы получить рабочий экземпляр».

Способность решать сложную вещь одним словом весьма полезна.

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

 interface IReport { string RenderReport(); } class MyNewReport : IReport { public string RenderReport() { return "Hello World Report!"; } } class AnotherReport : IReport { public string RenderReport() { return "Another Report!"; } } //This class can process any report that implements IReport! class ReportEmailer() { public void EmailReport(IReport report) { Email(report.RenderReport()); } } class MyApp() { void Main() { //create specific "MyNewReport" report using interface IReport newReport = new MyNewReport(); //create specific "AnotherReport" report using interface IReport anotherReport = new AnotherReport(); ReportEmailer reportEmailer = new ReportEmailer(); //emailer expects interface reportEmailer.EmailReport(newReport); reportEmailer.EmailReport(anotherReport); } } - interface IReport { string RenderReport(); } class MyNewReport : IReport { public string RenderReport() { return "Hello World Report!"; } } class AnotherReport : IReport { public string RenderReport() { return "Another Report!"; } } //This class can process any report that implements IReport! class ReportEmailer() { public void EmailReport(IReport report) { Email(report.RenderReport()); } } class MyApp() { void Main() { //create specific "MyNewReport" report using interface IReport newReport = new MyNewReport(); //create specific "AnotherReport" report using interface IReport anotherReport = new AnotherReport(); ReportEmailer reportEmailer = new ReportEmailer(); //emailer expects interface reportEmailer.EmailReport(newReport); reportEmailer.EmailReport(anotherReport); } } 

Интерфейсы также являются ключом к polymorphismу, одному из «ТРИ ОЧКОВ ООД».

Некоторые люди коснулись этого выше, polymorphism просто означает, что данный class может принимать разные «формы». Значение, если у нас есть два classа: «Собака» и «Кошка», и оба реализуют интерфейс «INeedFreshFoodAndWater» (hehe) – ваш код может сделать что-то вроде этого (псевдокод):

 INeedFreshFoodAndWater[] array = new INeedFreshFoodAndWater[]; array.Add(new Dog()); array.Add(new Cat()); foreach(INeedFreshFoodAndWater item in array) { item.Feed(); item.Water(); } 

Это мощно, потому что позволяет вам абстрактно относиться к различным classам объектов и позволяет делать такие вещи, как сделать ваши объекты более слабо связанными и т. Д.

Хорошо, так что речь идет об абстрактных classах против интерфейсов …

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

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

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

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

Интерфейсы описывают функциональность, а не реализацию.

Проще говоря: Интерфейс – это class, который определяет методы, но не реализует их. Напротив, у абстрактного classа есть некоторые из реализованных методов, но не все.

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

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

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

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

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

Как говорили другие, интерфейсы определяют контракт (как classы, которые используют интерфейс, будут «смотреть»), а абстрактные classы определяют общую функциональность.

Посмотрим, поможет ли код:

 public interface IReport { void RenderReport(); // this just defines the method prototype } public abstract class Reporter { protected void DoSomething() { // this method is the same for every class that inherits from this class } } public class ReportViolators : Reporter, IReport { public void RenderReport() { // some kind of implementation specific to this class } } public class ClientApp { var violatorsReport = new ReportViolators(); // the interface method violatorsReport.RenderReport(); // the abstract class method violatorsReport.DoSomething(); } 

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

Скажем, у вас есть:

 public interface ICommand { void Execute(); } public class PrintSomething : ICommand { OutputStream Stream { get; set; } String Content {get; set;} void Execute() { Stream.Write(content); } } 

Теперь у вас есть подстановочная структура команд. Любой экземпляр classа, который реализует IExecute, может быть сохранен в списке какого-то рода, скажем что-то, что реализует IEnumerable, и вы можете его пропустить и выполнить каждый, зная, что каждый объект будет просто делать правильную вещь. Вы можете создать составную команду, реализовав CompositeCommand, который будет иметь свой собственный список команд для запуска, или LoopingCommand для многократного запуска набора команд, тогда у вас будет большинство простых интерпретаторов.

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

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

Посмотрите на принцип либерализации Лискова, чтобы понять это.

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

Обновление Поскольку вы, кажется, спрашиваете об абстрактных classах с интерфейсами, вот мое предпочтительное упрощение:

  • Интерфейсы определяют возможности и функции.
  • Абстрактные classы определяют основные функциональные возможности.

Как правило, перед обработкой абстрактного classа я выполняю рефакторинг интерфейса экстракта. Я, скорее всего, создам абстрактный class, если я думаю, что должен существовать контракт на создание (в частности, что конкретный тип конструктора всегда должен поддерживаться подclassами). Тем не менее, я редко использую «чистые» абстрактные classы в C # / java. У меня гораздо больше шансов реализовать class с хотя бы одним методом, содержащим содержательное поведение, и использовать абстрактные методы для поддержки методов шаблонов, вызываемых этим методом. Тогда абстрактный class является базовой реализацией поведения, которое все конкретные подclassы могут использовать без необходимости переопределения.

Простой ответ: интерфейс представляет собой набор сигнатур методов (+ тип возврата). Когда объект говорит, что он реализует интерфейс, вы знаете, что он предоставляет этот набор методов.

Интерфейсы – это способ реализации соглашений таким образом, который все еще строго типизирован и полиморфен.

Хороший пример реального мира был бы IDisposable в .NET. Класс, реализующий интерфейс IDisposable, заставляет этот class реализовать метод Dispose (). Если class не реализует Dispose (), вы получите ошибку компилятора при попытке построить. Кроме того, этот код:

 using (DisposableClass myClass = new DisposableClass()) { // code goes here } 

Вызов myClass.Dispose () будет выполняться автоматически, когда выполнение выходит из внутреннего блока.

Однако, и это важно, нет никакого применения в отношении того, что должен сделать ваш метод Dispose (). Вы могли бы заставить свой метод Dispose () выбирать случайные рецепты из файла и отправлять их по электронной почте в список рассылки, компилятору все равно. objective шаблона IDisposable – облегчить очистку ресурсов. Если экземпляры classа будут помещаться в дескрипторы файлов, тогда IDisposable позволяет легко централизовать код удаления и очистки в одном месте и продвигать стиль использования, который гарантирует, что освобождение всегда происходит.

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

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

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

Например, интересующая вас последовательность не имеет ничего общего с первичными ключами в записях. С помощью объекта, реализующего интерфейс, вы можете сказать myObject.next () или myObject.prev ().

У меня была та же проблема, что и вы, и я нахожу объяснение «контракта» немного запутанным.

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

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

Еще одно предложение – переименовать интерфейс в class интерфейса, поскольку интерфейс – это еще один вариант classа.

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

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

  1. Члены производного classа могут использовать общедоступные или защищенные члены базового classа как свои собственные.
  2. Members of a derived class can be used by code which expects a member of the base class (meaning they are substitutable).

Both of these features are useful, but because it is difficult to allow a class to use members of more than one class as its own, many languages and frameworks only allow classes to inherit from a single base class. On the other hand, there is no particular difficulty with having a class be substitutable for multiple other unrelated things.

Further, because the first benefit of inheritance can be largely achieved via encapsulation, the relative benefit from allowing multiple-inheritance of the first type is somewhat limited. On the other hand, being able to substitute an object for multiple unrelated types of things is a useful ability which cannot be readily achieved without language support.

Interfaces provide a means by which a language/framework can allow programs to benefit from the second aspect of inheritance for multiple base types, without requiring it to also provide the first.

Most of the interfaces you come across are a collection of method and property signatures. Any one who implements an interface must provide definitions to what ever is in the interface.

Interface is like a fully abstract class. That is, an abstract class with only abstract members. You can also implement multiple interfaces, it’s like inheriting from multiple fully abstract classes. Anyway.. this explanation only helps if you understand what an abstract class is.

Moved to this question after this question was closed as a duplicate, in hope that it will help someone:

In your simple case, you could achieve something similar to what you get with interfaces by using a common base class that implements show() (or perhaps defines it as abstract). Let me change your generic names to something more concrete, Eagle and Hawk instead of MyClass1 and MyClass2 . In that case you could write code like

 Bird bird = GetMeAnInstanceOfABird(someCriteriaForSelectingASpecificKindOfBird); bird.Fly(Direction.South, Speed.CruisingSpeed); 

That lets you write code that can handle anything that is a Bird . You could then write code that causes the Bird to do it’s thing (fly, eat, lay eggs, and so forth) that acts on an instance it treats as a Bird . That code would work whether Bird is really an Eagle , Hawk , or anything else that derives from Bird .

That paradigm starts to get messy, though, when you don’t have a true is a relationship. Say you want to write code that flies things around in the sky. If you write that code to accept a Bird base class, it suddenly becomes hard to evolve that code to work on a JumboJet instance, because while a Bird and a JumboJet can certainly both fly, a JumboJet is most certainly not a Bird .

Enter the interface.

What Bird (and Eagle , and Hawk ) do have in common is that they can all fly. If you write the above code instead to act on an interface, IFly , that code can be applied to anything that provides an implementation to that interface.

Interfaces require any class that implements them to contain the methods defined in the interface.

The purpose is so that, without having to see the code in a class, you can know if it can be used for a certain task. For example, the Integer class in Java implements the comparable interface, so, if you only saw the method header (public class String implements Comparable), you would know that it contains a compareTo() method.

  • Почему оба родительского и дочернего classов реализуют один и тот же интерфейс?
  • Метод передачи Java в качестве параметра
  • Как создать class Java, который реализует один интерфейс с двумя универсальными типами?
  • Как выполнить бинарный поиск в IList ?
  • Каково фактическое использование интерфейса в java?
  • Как реализовать интерфейс IComparable?
  • Java - объявление из типа интерфейса вместо classа
  • Отражение Java: создание classа реализации
  • Если интерфейс Marker не имеет каких-либо методов, как он работает?
  • внутренний class внутри интерфейса
  • Зачем использовать интерфейсы, множественное наследование и интерфейсы, преимущества интерфейсов?
  • Давайте будем гением компьютера.