Когда нужно использовать интерфейсы?

По-видимому, с некоторыми сборками отладки существует опция, которая выводит собственный компонент (JIT) ассемблерный код от HotSpot: http://weblogs.java.net/blog/kohsuke/archive/2008/03/deep_dive_into.html

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

42
задан Ravindra babu 17 September 2016 в 18:03
поделиться

13 ответов

In languages such as Java and C# interfaces provide a means for a class to be have in a polymorphic manner. That is to say a class can satisfy more than one contract - it can behave as multiple different types, a class of one type can be substituted for another. In other languages this can also be provided by multiple inheritance, but there are various disadvantages to this approach. However, having a class behave as more than one type is not the most common motivation for using interfaces.

By programming to interfaces instead of classes you can also decouple your program from specific implementations. This makes it much easier to substitute one class implementation for another. This is particularly useful when writing unit tests where you may wish to swap some heavyweight class implementation with a lightweight mock object. If your program only expects an interface type, and both the heavyweight object and mock object implement said interface, then they are very easy to substitute.

Also, consider a simple Java example where I say have a program that displays pages of data on the screen. Initially I want it to get the data from a database or XML files. If I write my program so that it uses interfaces I can define an interface like so:

public interface PageDatasource {
    public List<Page> getPages();
}

And use it like so:

PageDatasource datasource = // insert concrete PageDatasource implementation here
List<Pages> pages = datasource.getPages();
display(pages);

I can then write separate database and XML implementations that adhere to this interface:

public class DatabasePageDatasource implements PageDatasource {
    public List<Page> getPages() {
        // Database specific code
    }
}

public class XmlPageDatasource implements PageDatasource {
    public List<Page> getPages() {
        // XML specific code
    }
}

Because I used an interface I can now use either implementation - Database or XML - interchangeably without having to change the parts of my program that ask for the page data. The XML and Database implementations likely do completely different things but all my program cares about is that the object supplying the page data implements the PageDatasource interface.

53
ответ дан 26 November 2019 в 23:20
поделиться

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

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

1
ответ дан 26 November 2019 в 23:20
поделиться

Java lang does not support multiple inheritance since interfaces are used to achieve the goal.

For a class to be abstract only 1 method has to be abstract ; Whereas in case of interface all methods are abstract .

1
ответ дан 26 November 2019 в 23:20
поделиться

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

1
ответ дан 26 November 2019 в 23:20
поделиться

One reason to use interfaces is when a class will implement a number of interfaces. An abstract class cannot do that.

One example is a class which handles mouse movement and key presses will implement both the (ficticious) IMouseMove and IKeyPress interfaces.

1
ответ дан 26 November 2019 в 23:20
поделиться

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

Пример:

public abstract class A {
    public void myFunc() {
        //do some work
    }
}

public class B : A {
    private void someOtherFunc() {
        base.myFunc();
    }
}

public class Z {
    public void exampleFunc() {
        //call public base class function exposed through extending class:
        B myB = new B();
        myB.myFunc();

        //explicitly cast B to A:
        ((A) myB).myFunc();

        //'A' cannot be created directly, do implicit cast down to base class:
        A myA = new B();
        myA.myFunc();
    }
}

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

public class Z {
    public void exampleFunc() {
        C myC = new C();
        //these two calls both call the same function:
        myC.myFunc();
        ((IExampleInterface1)myC).myFunc();

        D myD = new D();
        //hmmm... try and work out what happens here, which myFunc() gets called?
        //(clue: check the base class)
        myD.myFunc();

        //call different myFunc() in same class with identical signatures:
        ((IExampleInterface1)myD).myFunc();
        ((IExampleInterface2)myD).myFunc();
    }
}

interface IExampleInterface1
{
    void myFunc();
}

interface IExampleInterface2
{
    void myFunc();
}

public class C : IExampleInterface1
{
    public void myFunc()
    {
        //do stuff
    }
}

public class D : A, IExampleInterface1, IExampleInterface2
{
    void IExampleInterface1.myFunc()
    {
        //this is called when D is cast as IExampleInterface1
    }

    void IExampleInterface2.myFunc()
    {
        //this is called when D is cast as IExampleInterface2
    }
}
2
ответ дан 26 November 2019 в 23:20
поделиться

An interface is better than an abstract class because you can implement multiple interfaces, and you can only inherit from one abstract class.

So you can do:

class MyRow extends AbstractRow implements ISearchable, ISortable
{

}

Also, search StackOverflow for other similar questions like Need of interfaces in c#

4
ответ дан 26 November 2019 в 23:20
поделиться

To add to previous answers, interfaces help you during unit testing by allowing you to inject a mock object based on an interface into your code, allowing you to simulate specific scenarios and also to isolate your unit test to a specific component without relying on external components.

For example, suppose you have a business logic class that uses a data logic class to retrieve data from a data source and then process it. By creating an interface for the data logic class which it then inherits, you could create a mock/fake instance of that class based on the interface and inject that into the business logic class you're unit testing. The mocked instance can be defined so as to expect certain method/property calls, throw exceptions at certain points, return valid outputs etc etc. This means, your unit tests can run quicker/potentially more reliably as they are not reliant on the underlying data source being available/don't actually have to connect to it. And you're isolating the unit test down to a specific unit of code.

4
ответ дан 26 November 2019 в 23:20
поделиться

The reason interfaces exist is due to the 2 principle concepts of OOP, which is "identity" and "functionality"

Classes have functionality and an identity. With inheritance, objects instantiated can have a lot of functionality and multiple identities.

Interfaces are an identity without functionality. The functionality will be provided by the class instantiated.

The third form, a "mixin" is functionality without identity. Programming languages like ruby provide this third form of inheritance.

How you use an interface differs by the context of your programming language and your circumstances, but just remember, interfaces are used to define identities which are enforced onto objects.

7
ответ дан 26 November 2019 в 23:20
поделиться

At first glance, abstract classes and interfaces seem like a no-brainer. Why provide just an interface when you can also provide some base implementation? After investigation, you'll find that there is more to this.

That said, there are a number of reasons to use interfaces. You can find a decent blog post about the differences here.

That said, consider the fact that you can create an interface (a "contract" that says your class definitely supports certain calls/method signature invocations), but you can only provide a single abstract class. Also consider the fact that you can create an abstract class that also implements one or many interfaces, and inherit from this. This isn't a edge-case. This is actually done quite frequently in API's meant for high extensibility.

Check out the blog post I pointed you to and you should get a thorough understanding of when to use each and why you would use them. I would also highly recommend a good book such as "CLR via C#" by Microsoft Press. You'll learn a great deal!

7
ответ дан 26 November 2019 в 23:20
поделиться

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

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

В моей первой реализации разработчик IReader получает данные из базы данных SQL, а разработчик IWriter отправляет их через клиент веб-службы. Однако в конечном итоге мы создадим других разработчиков на обоих концах для доступа к другим репозиториям (FTP-сайты, каталоги файлов на локальном сетевом диске и т. Д.).

Все это время процессор в середине не заботится и не заботится не меняю. Он просто общается через эти стандартные интерфейсы.

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

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

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

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

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

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

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

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

8
ответ дан 26 November 2019 в 23:20
поделиться

Это проблема дизайна (я говорю о мире Java).

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

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

Пример:

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

Вы можете использовать абстрактный класс SenderCommunication с методом boolean sendWithSuccefull (...) если вы уверены, что поведение часто не изменится.

Вы можете использовать интерфейс InterfaceSenderCommunication с методом boolean sendWithSuccefull (...), если вы 'я не уверен, что поведение не будет часто меняться.

Конечно, суждение «менять часто - не часто» зависит от 2 элементов:

  • Сколько времени я должен потратить на синхронизацию старый код с новыми спецификациями?
  • Сколько платит покупатель? ;)
2
ответ дан 26 November 2019 в 23:20
поделиться

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

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

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

Теперь давайте ' s говорят, что вы хотите реализовать механизм сохранения для каталога библиотеки. Вы решили, что хотите хранить некоторые данные в базе данных, некоторые данные в файлах XML и некоторые данные в файлах с разделителями-запятыми. Итак, вопрос теперь в том, как вы можете сделать это полиморфным способом, который позволит вам иметь дело с общим API персистентности?

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

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

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

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

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

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

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

некоторые данные в файлах XML и некоторые данные в файлах с разделителями-запятыми. Итак, вопрос теперь в том, как вы можете сделать это полиморфным способом, который позволит вам иметь дело с общим API персистентности?

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

Итак, вопрос теперь в том, как вы можете сделать это полиморфным способом, который позволит вам иметь дело с общим API персистентности?

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

Итак, вопрос теперь в том, как сделать это полиморфным способом, который позволит вам иметь дело с общим API персистентности?

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

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

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

10
ответ дан 26 November 2019 в 23:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: