Вопрос по c#, oop – Почему я должен пойти на интерфейсы в C #, когда я могу реализовать методы напрямую

88

Я знаю, что это очень простой вопрос, но интервьюер задал мне очень хитрый вопрос, и я был беспомощен :(

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

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

conn.Dispose(); в конце концов блок. Но я не вижу, чтобы класс реализовывал или наследовалIDisposable интерфейс (SqlConnectionкласс я имею ввиду. Мне интересно, как я могу просто назвать имя метода. Кроме того, я не понимаю, как работает метод Dispose, потому что нам нужно реализовать тело функции с нашей собственной реализацией для всех методов интерфейса. Так как интерфейсы принимаются или называются контрактами? Эти вопросы до сих пор были в моей голове, и, честно говоря, я никогда не видел ни одной хорошей темы, которая могла бы объяснить мои вопросы так, чтобы я мог понять.

MSDN как обычно выглядит очень страшно и ни одной строки там не видно (Folks, kindly excuse who are into high level development, I strongly feel that any code or article should reach the mind of anyone who see it, hence like many others say, MSDN is not of use).

Интервьюер сказал:

У него есть 5 методов, и он с удовольствием реализует их непосредственно в классе, но если вам нужен класс или интерфейс Abstract, какой из них вы выберете и почему? Я ответил ему на все материалы, которые я прочитал в различных блогах, говоря о преимуществах и недостатках как абстрактного класса, так и интерфейса, но он не убежден, он пытается понять «Почему интерфейс»? в общем. & quot; Зачем нужен абстрактный класс & quot; в общем, даже если я могу реализовать одни и те же методы только один раз и не буду менять это.

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

SqlConnection наследуетсяSystem.ComponentModel.Component который реализуетIDisposable. Lee
О, Ли, это заставило меня понять, спасибо. Но я до сих пор не вижу, как или где "Утилизировать" функциональность метода определена. Learner
Интерфейсы - это то, что я изо всех сил пытался понять. Хороший вопрос. Brian
программирование для абстрактного контракта, а не для конкретной реализации .... Короче говоря, это означает, что вы можете заменить любой объект, который реализует интерфейс, когда требуется интерфейс. Mitch Wheat
@ MitchWheat - это не пример, вопрос в том, какSqlConnection инвентарьIDisposable. Lee

Ваш Ответ

14   ответов
80

 using System;

namespace MyInterfaceExample
{
    public interface IMyLogInterface
    {
        //I want to have a especific method that I'll use in MyLogClass
        void WriteLog();       
    }

    public class MyClass:IMyLogInterface
    {

        public void WriteLog()
        {
            Console.Write("MyClass was Logged");
        }
    }

    public class MyOtherClass :IMyLogInterface
    {

        public void WriteLog()
        {
            Console.Write("MyOtherClass was Logged");
            Console.Write("And I Logged it different, than MyClass");
        }
    }

    public class MyLogClass
    {
        //I created a WriteLog method where I can pass as parameter any object that implement IMyLogInterface.
        public static void WriteLog(IMyLogInterface myLogObject)
        {
            myLogObject.WriteLog(); //So I can use WriteLog here.
        }
    }

    public class MyMainClass
    {
        public void DoSomething()
        {
            MyClass aClass = new MyClass();
            MyOtherClass otherClass = new MyOtherClass();

            MyLogClass.WriteLog(aClass);//MyClass can log, and have his own implementation
            MyLogClass.WriteLog(otherClass); //As MyOtherClass also have his own implementation on how to log.
        }
    }
}

В моем примере я мог бы быть разработчиком, который пишетMyLogClassи другие разработчики могут создавать свои классы, и когда они хотят войти, они реализуют интерфейсIMyLogInterface, Это как они спрашивали меня, что они должны реализовать, чтобы использоватьWriteLog() метод вMyLogClass, Ответ они найдут в интерфейсе.

Эй, это похоже на очень хороший ингредиент для меня, чтобы понять, я действительно ценю это, большое спасибо :) :) Learner
Мой вопрос, если вы создаетеMyClass а такжеMyOtherClass почему бы вам просто не позвонитьaClass.WriteLog() зачем добавлять этот дополнительный шаг. РеализацияWriteLog() останется разным для каждого из классов, но у вас уже есть объект, так зачем передавать его в класс обработчика?
Разве это не пример для стратегии?
Хм, может случиться так, что если вы поместите свой пример регистрации на самородок, то другим будет проще использовать ваш регистратор, не зная подробностей ... но, с другой стороны, все же это не какой-то универсальный класс (например, я мог бы написать интерфейс с уровнями логирования и уровня аллергии) интерфейсы все еще только в вашей области. так что кроме вас, кому это выгодно?
@ZachM. Если я прав, значит ответ таков: он не будет создавать экземпляры классов, но другие разработчики будут создавать экземпляры классов и передавать его в качестве параметраMyLogClass WriteLog метод. Таким образом, его метод может обрабатывать любой объект, который реализуетIMyLogInterface . Here еще один интересный пост.
1

Идея контракта заключается в том, что вы указываете какое-то поведение. Если вы говорите, что реализовали, вы согласились с контрактом.

Выбор реферата поверх интерфейса есть.

Любой неабстрактный потомок абстрактного класса будет реализовывать контракт.

против

Любой класс, который реализует интерфейс, будет реализовывать контракт.

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

14

enter image description here

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

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

38

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

Why Interface You don't have default or shared code implementation You want to share data contracts (web services, SOA) You have different implementations for each interface implementer (IDbCommand has SqlCommand and OracleCommand which implement the interface in specific ways) You want to support multiple inheritance. Why Abstract You have default or shared code implementation You want to minimize code duplication You want to easily support versioning
Для практического примера, касающегося интерфейсов и SOA, мыshare our WCF Interfaces (DataContracts) в сборке .NET (e.g. Contracts.Shared.dll) так что клиенты .NET клиенты могут легкоinteroperate using ChannelFactory (avoiding generating code via Add Service Reference, etc.) или используяAdd Service Reference with Shared Types
@ Серебро Я читаю большинство из того, что вы напечатали в блогах, но я пытаюсь понять практически. Я сделал WCF-сервисы, открыл интерфейсы (но это было только одно отдельное приложение без восходящего или нисходящего потоков). Следовательно, я не мог понять это должным образом, хотя я очень хорошо проектировал и реализовывал интерфейсы. Мой вопрос, на самом деле, вы просто разделяете методы имен означает, правильно? КАК ЭТО ПОЛЕЗНО :( Я знаю, что это просто заставляет реализовывать все методы, но как иначе? В вашем посте выше, посвященном интерфейсу, 2-й пункт говорит «поделиться», значит, вы можете привести практический пример этого в реальном времени? Learner
0

Оба из 'Array' и «Список»; есть интерфейсIList, Мы создаем образец со строкой [] и списком и делаем некоторые общие тесты, используяIList:

string[] col1 = { "zero", "one", "two", "three", "four"};
List<string> col2 = new List<string>{ "zero", "one", "two", "three"};

static void CheckForDigit(IList collection, string digit)
    {
        Console.Write(collection.Contains(digit));
        Console.Write("    ");
        Console.WriteLine(collection.ToString());
    }

static void Main()
{
    CheckForDigit(col1, "one");   //True    System.String[]
    CheckForDigit(col2, "one");   //True    System.Collections.Generic.List`1[System.String]



//Another test:

    CheckForDigit(col1, "four");   //True    System.String[]
    CheckForDigit(col2, "four");   //false   System.Collections.Generic.List`1[System.String]
}
18

Polymorphism!

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

Look into Dependency Injection and definitely read Design Patterns - Elements of Reusable Object-Oriented Software by GOF.
1

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

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

1

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

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

Теперь давайте покопаемся по ссылке, которую я уже дал.

У тебя естьVehicle класс, который может измениться по требованию пользователя (например, добавлениеTruck, Tank, Airplaneи т. д. И учитывая, что мы имеем

public class clsBike:IChoice
{
   #region IChoice Members
    public string Buy()
    {
       return ("You choose Bike");
    }
    #endregion
}

а также

public class clsCar:IChoice
{
   #region IChoice Members
    public string Buy()
    {
       return ("You choose Car");
    }
    #endregion
}

и оба имеют Контракт IChoice, который просто говорит, что Мой класс должен иметь метод Buy

public interface IChoice
{
    string Buy();
}

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

public abstract class Choice
{
    public abstract string Discount { get; }
    public abstract string Type { get; }
    public string Buy()
    {
       return "You buy" + Type + " with " + Discount;
}
public class clsBike: Choice
{
    public abstract string Discount { get { return "10% Discount Off"; } }
    public abstract string Type { get { return "Bike"; } }
}

public class clsCar:Choice
{
    public abstract string Discount { get { return " $15K Less"; } }
    public abstract string Type { get { return "Car"; } }
}

Теперь, используя класс Factory, вы можете достичь того же, но используя abstract, вы позволяете базовому классу выполнятьBuy() метод.

In Summary : Interface contracts let the inherit class do the implementation while Abstract class Contracts may initialize the implementation (which can override by Inherit class)

38

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

  public void DoSomething(Account account) {
  // Do awesome stuff here.
}

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

public void DoSomething(IAccount account) {
  // Do awesome stuff here.
}

Это решение не привязано к реализации, что означает, что я могу передать ему SuperSavingsAccount или ExclusiveAccount (оба реализуют интерфейс IAccount) и получить различное поведение для каждой реализованной учетной записи.

спасибо за это объяснение! имеет смысл!
Хорошее объяснение
-1

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

Например, если у меня есть две сущности: «Животное» и «Человек», то я перейду к «Интерфейсу», где, как если бы мне нужно было подробно рассказать «Тигр, лев и хочу общаться с животным», тогда я выберу «Животный класс».

будет выглядеть ниже

   Interface             
   ____|____
  |        |
Animal   Human



  Animal (Abstract class)
   __|___
  |      |
Tiger   Lion
0

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

Хорошо сказано в вашем первом заявлении. Но я не понимаю вашего второго утверждения. Не могли бы вы уточнить пример в реальном времени? Learner
1

1) Создайте отдельные интерфейсы, которые предлагают различные варианты реализации, позволяя создать более целостный интерфейс.

2) Разрешить несколько методов с одинаковым именем между интерфейсами, потому что у вас нет конфликтующей реализации, только подпись.

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

4) Ваш код может полагаться на абстракцию, а не на конкретность, что позволяет внедрять умные зависимости, в том числе вводить тестовые макеты и т. Д.

Я уверен, что есть еще много причин, и это только несколько.

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

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

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

В .net4 вы можете получить что-то вроде утилитного типа с динамическим типом.
0

потому что я думаю, что вы очень хорошо знаете теорию, и я предполагаю, что вы знаете принципы SOLID, так что давайте начнем практиковать.

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

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

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

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