Как узнать, когда создавать интерфейс?
Я нахожусь в одном месте в своем обучении развитию, где мне кажется, что я должен больше узнать о интерфейсах.
Я часто читаю о них, но кажется, что я не могу их понять.
Я читал такие примеры, как: базовый class животных, с интерфейсом IAnimal для таких вещей, как «Прогулка», «Запуск», «GetLegs» и т. Д., Но я никогда не работал над чем-то и чувствовал себя «Эй, я должен использовать интерфейс Вот!”
- Platform.runLater и задача в JavaFX
- Как выполнить бинарный поиск в IList ?
- Установка IP-адреса источника для гнезда UDP
- Интерфейсы C #. Неявная реализация по сравнению с явной реализацией
- Как вы быстро находите реализацию (ы) метода интерфейса?
Что мне не хватает? Почему мне так сложно понять? Меня просто запугивает тот факт, что я, возможно, никогда не осознаю конкретной потребности в одном – в основном из-за недостатка в их понимании! Это заставляет меня чувствовать, что мне не хватает чего-то высшего в плане того, чтобы быть разработчиком! Если у кого-то был такой опыт и был прорыв, я был бы признателен за некоторые советы о том, как понять эту концепцию. Спасибо.
- Зачем использовать интерфейсы, множественное наследование и интерфейсы, преимущества интерфейсов?
- Интерфейсы против абстрактных classов
- Как реализовать интерфейс IComparable?
- Реализует vs extends: Когда использовать? Какая разница?
- Не публичные пользователи для интерфейсов C #
- Каково фактическое использование интерфейса в java?
- Как вы это называете, когда один интерфейс «наследует» от другого?
- Оператор «instanceof» ведет себя по-разному для интерфейсов и classов
он решает эту конкретную проблему:
у вас есть a, b, c, d из 4 разных типов. во всем вашем коде у вас есть что-то вроде:
a.Process(); b.Process(); c.Process(); d.Process();
почему бы им не реализовать IPprocessable, а затем сделать
List list; foreach(IProcessable p in list) p.Process();
это значительно улучшится, если вы добавите, скажем, 50 типов classов, которые все делают одно и то же.
Еще одна конкретная проблема:
Вы когда-нибудь смотрели System.Linq.Enumerable? Он определяет тонну методов расширения, которые работают на любом типе, который реализует IEnumerable. Поскольку все, что реализует IEnumerable, в основном говорит: «Я поддерживаю итерацию в неупорядоченном шаблоне типа foreach», вы можете определить сложные поведения (Count, Max, Where, Select и т. Д.) Для любого перечислимого типа.
Мне нравится ответ Джимми, но я чувствую, что мне нужно что-то добавить. Ключом к этому является «способный» ansible IProcess. Он указывает на способность (или свойство, но значение «внутреннее качество», а не в смысле свойств C #) объекта, реализующего интерфейс. IAnimal, вероятно, не очень хороший пример для интерфейса, но IWalkable может быть хорошим интерфейсом, если ваша система имеет много вещей, которые могут ходить. У вас могут быть уроки, полученные от Animal, таких как Dog, Cow, Fish, Snake. Первые два, вероятно, будут реализовывать IWalkable, последние два не ходят, поэтому они не будут. Теперь вы спрашиваете: «Почему бы просто не получить еще один суперclass« WalkingAnimal », из которого вышла Собака и Корова?». Ответ заключается в том, что у вас есть что-то совершенно вне дерева наследования, которое также может ходить, например, робота. Робот будет реализовывать IWalkable, но, вероятно, не будет получен от Animal. Если вам нужен список вещей, которые могут ходить, вы вводите его как IWalkable, и вы можете поместить всех ходячих животных вместе с роботами в список.
Теперь замените IWalkable чем-то более программным, как IPersistable, и аналогия становится намного ближе к тому, что вы увидите в реальной программе.
Используйте интерфейсы, когда реализации одинаковой функциональности будут отличаться.
Используйте абстрактные / базовые classы, когда вам нужно совместно использовать общую конкретную реализацию.
Подумайте о интерфейсе, таком как Контракт. Это способ сказать: «Эти classы должны следовать этим правилам».
Поэтому в примере IAnimal это способ сказать: «Я ДОЛЖЕН иметь возможность вызывать Run, Walk и т. Д. На classах, которые реализуют IAnimal».
Почему это полезно? Возможно, вы захотите создать функцию, которая полагается на то, что вы должны иметь возможность вызвать Run и Walk, например, на объекте. У вас может быть следующее:
public void RunThenWalk(Monkey m) { m.Run(); m.Walk(); } public void RunThenWalk(Dog d) { d.Run(); d.Walk(); }
… и повторите это для всех объектов, которые, как вы знаете, могут бегать и ходить. Однако с помощью интерфейса IAnimal вы можете определить функцию один раз следующим образом:
public void RunThenWalk(IAnimal a) { a.Run(); a.Walk(); }
Путем программирования против интерфейса вы, по сути, доверяете classам для реализации намерения интерфейса. Таким образом, в нашем примере мы подумали: «Мне все равно, как они бегут и ходят, пока они бегут и ходят. Мой RunThenWalk будет действителен до тех пор, пока они выполнят это соглашение. Он отлично функционирует, не зная ничего о себе class.”
В этом связанном вопросе также есть хорошая дискуссия.
Не волнуйся. Многим разработчикам редко приходится писать интерфейс. Вы часто используете интерфейсы, доступные в рамках .NET , но если вы не чувствуете необходимости писать их в ближайшее время, в этом нет ничего удивительного.
Пример, который я всегда даю кому-то, – это если у вас есть class Sailboat и class Viper. Они наследуют class лодки и class автомобилей соответственно. Теперь скажите, что вам нужно пройти все эти объекты и вызвать их метод Drive()
. Хотя вы можете написать какой-то код, как показано ниже:
if(myObject is Boat) ((Boat)myObject).Drive() else if (myObject is Car) ((Car)myObject).Drive()
Было бы намного проще написать:
((IDrivable)myObject).Drive()
Джимми прав, когда вы хотите иметь возможность использовать одну переменную для нескольких типов, но все эти типы реализуют один и тот же метод с помощью объявления интерфейса. Затем вы можете назвать их основным методом для типизированной переменной интерфейса.
Однако есть вторая причина использовать интерфейсы. Когда архитектор проекта отличается от кодера реализации, или есть несколько кодеров реализации и один менеджер проектов. Ответственный человек может написать целую кучу интерфейсов и увидеть, что система взаимодействует, а затем оставить разработчикам возможность заполнить интерфейсы classами реализации. Это лучший способ гарантировать, что несколько человек пишут совместимые classы, и они могут делать это параллельно.
По моему опыту, движущей силой создания интерфейсов не было, пока я не начал выполнять модульное тестирование с насмешливой структурой. Стало совершенно ясно, что использование интерфейсов должно было сделать насмешкой намного проще (поскольку структура зависела от виртуальных методов). Как только я начал, я увидел ценность абстрагирования интерфейса от моего classа от реализации. Даже если я не создаю фактический интерфейс, я теперь пытаюсь сделать мои методы виртуальными (предоставляя неявный интерфейс, который можно переопределить).
Есть много других причин, которые я нашел, чтобы укрепить хорошую практику рефакторинга для интерфейсов, но модульное тестирование / издевательство было тем, что обеспечивало основной «аха-момент» практического опыта.
EDIT : Чтобы уточнить, с модульным тестированием и издевательством, у меня всегда есть две реализации – реальная, конкретная реализация и альтернативная макетная реализация, используемая при тестировании. Когда у вас есть две реализации, значение интерфейса становится очевидным – справляйтесь с ним в терминах интерфейса, чтобы вы могли в любой момент заменить его. В этом случае я заменяю его макетным интерфейсом. Я знаю, что могу сделать это без реального интерфейса, если мой class построен правильно, но использование реального интерфейса усиливает это и делает его более чистым (понятным для читателя). Без этого стимула я не думаю, что я бы оценил ценность интерфейсов, поскольку большинство моих classов только когда-либо имели одну конкретную реализацию.
Мне нравится армейская аналогия.
Сержанту все равно, если вы разработчик программного обеспечения , музыкант или адвокат .
Вас рассматривают как солдата .
Сержанту легче не беспокоиться о конкретных деталях лиц, с которыми он работает,
рассматривайте всех как абстракции солдат (… и наказывайте их, когда они не могут действовать как одни).
Способность людей действовать как солдат называется polymorphismом.
Интерфейсы – это программные конструкции, которые помогают достичь polymorphismа.
Необходимость абстрактных деталей для достижения простоты – ответ на ваш вопрос.
Полиморфизм , который этимологически означает «многие формы», – это способность обрабатывать объект любого подclassа базового classа, как если бы он был объектом базового classа. Поэтому базовый class имеет множество форм: самого базового classа и любого его подclassа.
(..) Это делает ваш код более легким для вас, чтобы писать и легче понять другим. Это также делает ваш код расширяемым, потому что другие подclassы могут быть добавлены позже в семейство типов, а объекты этих новых подclassов также будут работать с существующим кодом.
Некоторые примеры не-программирования, которые могут помочь вам увидеть правильное использование интерфейсов в программировании.
Существует интерфейс между электрическими устройствами и электрической сетью – это набор условных обозначений о форме разъемов и разъемов и напряжения / токи на них. Если вы хотите внедрить новое электрическое устройство, если ваш штекер соответствует правилам, он сможет получать услуги из сети. Это упрощает развертывание и снижает затраты на координацию : вам не нужно уведомлять поставщика электроэнергии о том, как работает ваше новое устройство, и прийти к отдельному соглашению о том, как подключить новое устройство к сети.
В странах есть стандартные железнодорожные манометры. Это позволяет разделить труд между инженерными компаниями, которые поставили rails и инженерные компании, которые строят поезда на этих рельсах, и это позволяет железнодорожным компаниям заменять и модернизировать поезда без перестройки всей системы.
Услуга, которую бизнес представляет клиенту, может быть описана как интерфейс: четко определенный интерфейс подчеркивает услугу и скрывает средства . Когда вы помещаете письмо в почтовый ящик, вы ожидаете, что почтовая система будет доставлять письмо в течение определенного времени, но у вас нет ожиданий о том, как доставлено письмо: вам не нужно знать , и почтовая служба имеет гибкость для выберите средства доставки, которые наилучшим образом соответствуют требованиям и текущим обстоятельствам. Исключением из этого является способность клиентов выбирать авиапочту – это не тот тип интерфейса, который бы запрограммировал современный программист, поскольку он показывает слишком большую часть реализации.
Примеры из природы: я не слишком увлечен примерами utes (), hasSound (), move () и т. Д. Они описывают поведение, которое является правильным, но они не описывают взаимодействия и способы их включения . Очевидные примеры интерфейсов, которые позволяют взаимодействовать в природе, связаны с воспроизведением, например, цветок предоставляет определенный интерфейс пчеле, так что опыление может иметь место.
Вполне возможно, что вы всю жизнь проводите как разработчик .net и никогда не пишете свои собственные интерфейсы. В конце концов, мы выжили отлично без них на протяжении десятилетий, и наши языки все еще были Тьюрингом.
Я не могу сказать вам, почему вам нужны интерфейсы, но я могу дать вам список того, где мы их используем в нашем текущем проекте:
-
В нашей подключаемой модели мы загружаем подключаемые модули по интерфейсу и предоставляем этот интерфейс совместимым сценариям.
-
В нашей межмашинной системе обмена сообщениями classы сообщений реализуют определенный интерфейс и «разворачиваются» с использованием интерфейса.
-
Наша система управления конфигурацией определяет интерфейс, используемый для установки и получения настроек конфигурации.
-
У нас есть один интерфейс, который мы используем, чтобы избежать неприятной круглой справки. (Не делайте этого, если вам не нужно.)
Я думаю, что если есть правило, использовать интерфейсы, если вы хотите сгруппировать несколько classов в отношениях is-a, но вы не хотите предоставлять какую-либо реализацию в базовом classе.
Пример кода (комбинация Эндрю с дополнительными моими в чем-то-на-цели-интерфейсах ), который также делает случай, почему интерфейс вместо абстрактного classа на языках без поддержки множественного наследования (c # и Ява):
interface ILogger { void Log(); } class FileLogger : ILogger { public void Log() { } } class DataBaseLogger : ILogger { public void Log() { } } public class MySpecialLogger : SpecialLoggerBase, ILogger { public void Log() { } }
Обратите внимание, что FileLogger и DataBaseLogger не нуждаются в интерфейсе (может быть абстрактным базовым classом Logger). Но учтите, что вам необходимо использовать сторонний регистратор, который заставляет вас использовать базовый class (скажем, он предоставляет защищенные методы, которые вам нужно использовать). Поскольку язык не поддерживает множественное наследование, вы не сможете использовать подход абстрактного базового classа.
Нижняя линия: используйте интерфейс, когда это возможно, чтобы получить дополнительную гибкость в коде. Ваша реализация менее привязана, поэтому она лучше подходит для перемен.
Я использовал интерфейсы время от времени, и вот мое последнее использование (имена были обобщены):
У меня есть набор пользовательских элементов управления в WinForm, которые должны сохранять данные в моем бизнес-объекте. Один из подходов состоит в том, чтобы вызвать каждый элемент управления отдельно:
myBusinessObject.Save(controlA.Data); myBusinessObject.Save(controlB.Data); myBusinessObject.Save(controlC.Data);
Проблема с этой реализацией заключается в том, что в любое время, когда я добавляю элемент управления, я должен войти в мой метод «Сохранить данные» и добавить новый элемент управления.
Я изменил свои элементы управления для реализации интерфейса ISaveable, который имеет метод SaveToBusinessObject (…), поэтому теперь мой метод «Сохранить данные» просто выполняет итерации с помощью элементов управления, и если он находит тот, который является ISaveable, он вызывает SaveToBusinessObject. Итак, теперь, когда нужен новый элемент управления, все, что нужно сделать, это реализовать ISaveable в этом объекте (и никогда не касаться другого classа).
foreach(Control c in Controls) { ISaveable s = c as ISaveable; if( s != null ) s.SaveToBusinessObject(myBusinessObject); }
Часто нереализованная польза для интерфейсов заключается в том, что вы локализуете модификации. После определения вы редко меняете общий stream приложения, но вы часто вносите изменения на уровне детализации. Когда вы сохраняете детали в конкретных объектах, изменение в ProcessA не повлияет на изменение в ProcessB. (Базовые classы также дают вам это преимущество.)
EDIT: Еще одно преимущество – это специфичность действий. Как и в моем примере, все, что я хочу сделать, это сохранить данные; Мне все равно, какой тип контроля он или может сделать что-нибудь еще – я просто хочу знать, могу ли я сохранить данные в элементе управления. Это делает мой код сохранения довольно понятным – нет проверок, чтобы увидеть, является ли это текстовым, числовым, логическим или каким-либо другим, потому что пользовательский элемент управления обрабатывает все это.
Вы должны определить интерфейс, как только вам потребуется принудительное поведение для вашего classа.
Поведение Животного может включать в себя Прогулки, Питание, Бег и т. Д. Поэтому вы определяете их как интерфейсы.
Другим практическим примером является интерфейс ActionListener (или Runnable). Вы бы реализовали их, когда вам нужно отслеживать определенное событие. Поэтому вам необходимо предоставить реализацию actionPerformed(Event e)
в вашем classе (или подclassе). Аналогично, для интерфейса Runnable вы предоставляете реализацию для метода public void run()
.
Кроме того, вы можете использовать эти интерфейсы для любого количества classов.
Другой экземпляр, где используются интерфейсы (в Java), заключается в реализации множественного наследования, предлагаемого на C ++.
Предположим, вы хотите захотеть моделировать неприятности, которые могут возникнуть при попытке заснуть.
Модель перед интерфейсами
class Mosquito { void flyAroundYourHead(){} } class Neighbour{ void startScreaming(){} } class LampJustOutsideYourWindow(){ void shineJustThroughYourWindow() {} }
Как вы ясно видите, многие вещи могут быть раздражающими, когда вы пытаетесь спать.
Использование classов без интерфейсов
Но когда дело доходит до использования этих classов, у нас есть проблема. У них нет ничего общего. Вы должны вызывать каждый метод отдельно.
class TestAnnoyingThings{ void testAnnoyingThinks(Mosquito mosquito, Neighbour neighbour, LampJustOutsideYourWindow lamp){ if(mosquito != null){ mosquito.flyAroundYourHead(); } if(neighbour!= null){ neighbour.startScreaming(); } if(lamp!= null){ lamp.shineJustThroughYourWindow(); } } }
Модель с интерфейсами
Чтобы преодолеть эту проблему, мы можем ввести итерал
interface Annoying{ public void annoy(); }
И реализовать его внутри classов
class Mosquito implements Annoying { void flyAroundYourHead(){} void annoy(){ flyAroundYourHead(); } } class Neighbour implements Annoying{ void startScreaming(){} void annoy(){ startScreaming(); } } class LampJustOutsideYourWindow implements Annoying{ void shineJustThroughYourWindow() {} void annoy(){ shineJustThroughYourWindow(); } }
Использование с интерфейсами
Что значительно облегчит использование этих classов
class TestAnnoyingThings{ void testAnnoyingThinks(Annoying annoying){ annoying.annoy(); } }
Самый простой пример – это что-то вроде Платежных процессоров (Paypal, PDS и т. Д.).
Предположим, вы создали интерфейс IPaymentProcessor с методами ProcessACH и ProcessCreditCard.
Теперь вы можете реализовать конкретную реализацию Paypal. Эти методы называют специальными функциями PayPal.
Если вы решите позже, вам нужно переключиться на другого провайдера, вы можете. Просто создайте еще одну конкретную реализацию для нового провайдера. Поскольку все, к чему вы привязаны, это ваш интерфейс (контракт), вы можете поменять, какой из них использует ваше приложение, не меняя код, который его использует.
Он также позволяет выполнять тестирование модуля Mock (.Net). Если ваш class использует интерфейс, вы можете издеваться над объектом в тестировании вашего устройства и легко тестировать логику (без фактического попадания в базу данных или веб-сервис и т. Д.).
Если вы просматриваете сборки .NET Framework и переходите к базовым classам для любого из стандартных объектов, вы увидите много интерфейсов (членов, названных ISomeName).
Интерфейсы в основном предназначены для реализации фреймворков, больших или малых. Я чувствовал то же самое о интерфейсах, пока не захотел написать свою собственную структуру. Я также обнаружил, что понимание интерфейсов помогло мне быстрее изучить фреймворки. В тот момент, когда вы хотите написать более элегантное решение практически для чего угодно, вы обнаружите, что интерфейс имеет большой смысл. Это похоже на метод, позволяющий classу надеть подходящую одежду для работы. Что еще более важно, интерфейсы позволяют системам становиться намного более самодокументируемыми, потому что сложные объекты становятся менее сложными, когда class реализует интерфейсы, что помогает classифицировать его функциональность.
Классы реализуют интерфейсы, когда они хотят иметь возможность участвовать в структуре явно или неявно. Например, IDisposable – это общий интерфейс, который обеспечивает подпись метода для популярного и полезного метода Dispose (). В рамках всего, что вам или другому разработчику нужно знать о classе, является то, что если он реализует IDisposable, то вы знаете, что ((IDisposable) myObject) .Dispose () доступен для вызова для целей очистки.
КЛАССИЧЕСКИЙ ПРИМЕР: без реализации интерфейса IDisposable вы не можете использовать конструкцию ключевых слов «using ()» в C #, потому что для этого требуется, чтобы любой объект, указанный как параметр, мог быть неявным образом перенесен в IDisposable.
КОМПЛЕКСНЫЙ ПРИМЕР: Более сложным примером может быть class System.ComponentModel.Component. Этот class реализует как IDisposable, так и IComponent. Большинство, если не все, объекты .NET, имеющие связанный с ними визуальный дизайнер, реализуют IComponent, так что среда IDE сможет взаимодействовать с компонентом.
ЗАКЛЮЧЕНИЕ. По мере того, как вы более знакомы с .NET Framework, первое, что вы будете делать, когда сталкиваетесь с новым classом в обозревателе объектов или в инструменте .NET Reflector (бесплатно) ( http://www.red-gate.com / products / reflector / ) – проверить, какой class он наследует, а также интерфейсы, которые он реализует. .NET Reflector даже лучше, чем Object Browser, потому что он позволяет также видеть classы Derived. Это позволяет вам узнать обо всех объектах, которые происходят из определенного classа, тем самым потенциально узнавая о функциональности фреймворка, которые вы не знали. Это особенно важно, когда обновленные или новые пространства имен добавлены в .NET Framework.
Подумайте, что вы делаете первую стреляющую игру. У игрока есть несколько орудий на выбор.
Мы можем иметь интерфейс Gun
который определяет функцию shoot()
.
Нам нужны разные подclassы classа Gun
а именно ShotGun
Sniper
и т. Д.
ShotGun implements Gun{ public void shoot(){ \\shotgun implementation of shoot. } } Sniper implements Gun{ public void shoot(){ \\sniper implementation of shoot. } }
Класс шутера
У стрелка есть все оружие в его Доспехе. Позволяет создать List
для его представления.
List listOfGuns = new ArrayList ();
Стрелок проводит через свои пушки, когда и когда это необходимо, используя функцию switchGun()
public void switchGun(){ //code to cycle through the guns from the list of guns. currentGun = //the next gun in the list. }
Мы можем установить текущий пистолет, используя вышеуказанную функцию и просто вызвать функцию shoot()
, когда вызывается fire()
.
public void fire(){ currentGun.shoot(); }
Поведение функции съемки зависит от разных реализаций интерфейса Gun
.
Вывод
Создайте интерфейс, когда функция classа зависит от функции из другого classа , которая подвержена изменению ее поведения на основе экземпляра (объекта) реализованного classа.
например, функция fire()
из classа Shooter
ожидает, что пушки ( Sniper
, ShotGun
) реализуют функцию shoot()
. Поэтому, если мы включим пистолет и огонь.
shooter.switchGun(); shooter.fire();
Мы изменили поведение функции fire()
.
Расширить то, что сказал Ларсенал. Интерфейс – это контракт, которым должны следовать все реализующие classы. Из-за этого вы можете использовать технику, называемую программированием для контракта. Это позволяет вашему программному обеспечению стать независимым от реализации.
Интерфейсы обычно используются, когда вы хотите определить поведение, которое могут демонстрировать объекты.
Хорошим примером этого в мире .NET является интерфейс IDisposable , который используется на любых classах Microsoft, которые используют системные ресурсы, которые должны быть вручную выпущены. Это требует, чтобы class, реализующий его, имел метод Dispose ().
(Метод Dispose () также вызывается конструкцией языка использования для VB.NET и C # , которая работает только с IDisposable
s)
Имейте в виду, что вы можете проверить, реализует ли объект определенный интерфейс, используя такие конструкции, как TypeOf ... Is
(VB.NET), is
(C #), instanceof
(Java) и т. Д. …
Как уже несколько человек уже ответили, интерфейсы могут использоваться для обеспечения соблюдения определенных типов поведения между classами, которые не будут реализовывать эти поведения одинаково. Поэтому, реализуя интерфейс, вы говорите, что ваш class имеет поведение интерфейса. Интерфейс IAnimal не будет типичным интерфейсом, поскольку classы Dog, Cat, Bird и т. Д. Являются типами животных и, вероятно, должны расширять его, что является случаем наследования. Вместо этого интерфейс будет больше похож на поведение животных в этом случае, такое как IRunnable, IFlyable, ITrainable и т. Д.
Интерфейсы хороши для многих вещей, одна из ключевых особенностей – возможность подключения. Например, объявление метода, имеющего параметр List, позволит использовать все, что реализует интерфейс List, который должен быть передан, что позволяет разработчику удалять и подключать другой список позднее, не переписывая тонну кода.
Возможно, вы никогда не будете использовать интерфейсы, но если вы разрабатываете проект с нуля, особенно в какой-то структуре, вы, вероятно, захотите ознакомиться с ними.
Я бы рекомендовал прочитать главу о интерфейсах в Java Design от Coad, Mayfield и Kern. Они объясняют это немного лучше, чем средний вводный текст. Если вы не используете Java, вы можете просто прочитать начало главы, которая в основном представляет собой концепцию.
Как любая технология программирования, которая добавляет гибкость вашей системе, интерфейсы также добавляют некоторую сложность. Они часто велики, и вы можете использовать их повсюду (вы можете создать интерфейс для всех своих classов), но при этом вы создали бы более сложную систему, которую было бы сложнее поддерживать.
Существует компромисс здесь, как обычно: гибкость над ремонтопригодностью. Какой из них более важен? Ответов нет – это зависит от проекта. Но просто помните, что каждое программное обеспечение должно быть сохранено …
Поэтому мой совет: не используйте интерфейсы, пока они вам не понадобятся. (С Visual Studio вы можете извлечь интерфейс из существующего classа за 2 секунды – так что не спешите.)
Сказав это, когда вам нужно создать интерфейс?
Я делаю это, когда я реорганизую метод, который внезапно должен обрабатывать два или более подобных classа. Затем я создаю интерфейс, назначаю этот интерфейс двум (или более) аналогичным classам и меняю тип параметра метода (замените тип classа на тип интерфейса).
И это работает: o)
Одно исключение: когда я когда-то обманывал объекты, интерфейс намного проще в использовании. Поэтому я часто создаю интерфейс именно для этого.
PS: Когда я пишу «интерфейс», я имею в виду: «интерфейс любого базового classа», включая чистые classы интерфейса. Обратите внимание, что абстрактные classы часто лучше, чем чистые интерфейсы, поскольку вы можете добавить к ним логику.
С уважением, Сильвен.
Интерфейсы станут очевидными, когда вы станете разработчиком библиотеки (кто-то, кто кодов для других кодеров). Большинство из нас начинаются как разработчики приложений , где мы используем существующие API и библиотеки программирования.
В то же время, что интерфейсы являются контрактом , никто еще не упомянул, что интерфейсы – отличный способ сделать некоторые части вашего кода стабильными . Это особенно полезно, когда это командный проект (или когда вы разрабатываете код, используемый другими разработчиками). Итак, вот конкретный сценарий для вас:
Когда вы разрабатываете код в команде , другие могут использовать код, который вы пишете. Они будут очень счастливы, когда они закодируют ваши (стабильные) интерфейсы, и вы будете счастливы, когда у вас будет свобода менять свои реализации (скрытые за интерфейсом), не нарушая код вашей команды. Это вариант скрытия информации (интерфейсы общедоступны, реализации скрыты от клиентских программистов). Подробнее о защищенных вариантах .
Также см. Этот связанный вопрос о кодировании с интерфейсом .
Целесообразно использовать интерфейс.
-
Использование в полиморфном поведении. Если вы хотите вызывать конкретные методы дочернего classа с inteface, имеющим ссылку на дочерний class.
-
Наличие договора с classами для реализации всех методов, где это необходимо, как и наиболее распространенное использование с объектами COM, где class оболочки генерируется в DLL, которая наследует интерфейс; эти методы называются за кулисами, и вам просто нужно их реализовать, но с той же структурой, что и в COM-библиотеке, которую вы можете знать только через интерфейс, который они раскрывают.
-
Сокращение использования памяти путем загрузки определенных методов в class. Например, если у вас есть три бизнес-объекта, и они реализованы в одном classе, вы можете использовать три интерфейса.
Например, IUser, IOrder, IOrderItem
public interface IUser() { void AddUser(string name ,string fname); } // Same for IOrder and IOrderItem // public class BusinessLayer: IUser, IOrder, IOrderItem { public void AddUser(string name ,string fname) { // Do stuffs here. } // All methods from all interfaces must be implemented. }
Если вы хотите добавить пользователя, сделайте следующее:
IUser user = new (IUser)BusinessLayer(); // It will load all methods into memory which are declared in the IUser interface. user.AddUser();