Использование переменных интерфейса - PullRequest
37 голосов
/ 28 января 2010

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

Что я не понимаю, так это когда вы создаете переменную одного из типов вашего интерфейса:

IMyInterface somevariable;

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

somevariable.CallSomeMethod();

Зачем вам использовать переменную IMyInterface для этого?

Ответы [ 12 ]

63 голосов
/ 28 января 2010

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

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

Так что теперь, используя ваш пример, вы можете получить:

MyNiftyClass : IMyInterface
{
    public void CallSomeMethod()
    {
        //Do something nifty
    }
}

MyOddClass : IMyInterface
{
    public void CallSomeMethod()
    {
        //Do something odd
    }
}

А теперь у вас есть:

IMyInterface nifty = new MyNiftyClass()
IMyInterface odd = new MyOddClass()

Вызов метода CallSomeMethod теперь будет делать что-то изящное или что-то странное, и это становится особенно полезным, когда вы передаете использование IMyInterface в качестве типа.

public void ThisMethodShowsHowItWorks(IMyInterface someObject)
{
    someObject.CallSomeMethod();
}

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

public void AnotherClass()
{
    IMyInterface nifty = new MyNiftyClass()
    IMyInterface odd = new MyOddClass()

    // Pass in the nifty class to do something nifty
    this.ThisMethodShowsHowItWorks(nifty);

    // Pass in the odd class to do something odd
    this.ThisMethodShowsHowItWorks(odd);

}

EDIT

Это касается, как мне кажется, вашего намеченного вопроса: зачем вам объявлять переменную типа интерфейса?

То есть зачем использовать:

IMyInterface foo = new MyConcreteClass();

в предпочтении:

MyConcreteClass foo = new MyConcreteClass();

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

public void AMethod()
{
    // Why use this?
    IMyInterface foo = new MyConcreteClass();

    // Why not use this?
    MyConcreteClass bar = new MyConcreteClass();
}

Обычно нет технических причин, по которым интерфейс предпочтительнее. Я обычно использую интерфейс, потому что:

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

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

Заимствуя пример у itowlson, используя конкретную декларацию, вы не сможете сделать это:

public void AMethod(string input)
{               
    IMyInterface foo;

    if (input == "nifty")
    {
        foo = new MyNiftyClass();
    }
    else
    {
        foo = new MyOddClass();
    }
    foo.CallSomeMethod();
}
7 голосов
/ 28 января 2010

Потому что это:

public void ReadItemsList(List<string> items);
public void ReadItemsArray(string[] items);

может стать таким:

public void ReadItems(IEnumerable<string> items);

Редактировать

Думайте об этом так:

Вы должны быть в состоянии сделать это.

вместо:

Вы должны быть этим.

По сути, это контракт между методом и его вызывающими.

1 голос
/ 13 февраля 2017

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

 IDepartments rep = new DepartmentsImpl();

почему бы и нет

 DepartmentsImpl rep = new DepartmentsImpl();

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

class Test 
{
static void Main()
{
    SampleClass sc = new SampleClass();
    IControl ctrl = (IControl)sc;
    ISurface srfc = (ISurface)sc;

    // The following lines all call the same method.
    sc.Paint();
    ctrl.Paint();
    srfc.Paint();
}

}

interface IControl
{
  void Paint();
}
 interface ISurface
{
  void Paint();
}
 class SampleClass : IControl, ISurface
 {
   // Both ISurface.Paint and IControl.Paint call this method. 
 public void Paint()
 {
    Console.WriteLine("Paint method in SampleClass");
 }

}

 // Output:
 // Paint method in SampleClass
// Paint method in SampleClass
// Paint method in SampleClass

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

public class SampleClass : IControl, ISurface
{
    void IControl.Paint()
    {
        System.Console.WriteLine("IControl.Paint");
    }
    void ISurface.Paint()
    {
        System.Console.WriteLine("ISurface.Paint");
    }
}

Член класса IControl.Paint доступен только через интерфейс IControl, а ISurface.Paint доступен только через ISurface. Обе реализации метода являются отдельными, и ни одна из них не доступна непосредственно в классе. Например:

   IControl c = new SampleClass();
   ISurface s = new SampleClass();
   s.Paint();

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

1 голос
/ 28 января 2010

Использование интерфейсных переменных является ЕДИНСТВЕННЫМ способом, позволяющим писать методы-обработчики, которые могут принимать данные от объектов, имеющих разные базовые классы.

Это примерно так же ясно, как и любой другой.

1 голос
/ 28 января 2010

Допустим, у вас есть класс Лодка, Автомобиль, Грузовик, Самолет.

Все они имеют общий метод TakeMeThere (строка назначения)

У вас будет интерфейс:

public interface ITransportation
{
    public void TakeMeThere(string destination);
}

тогда ваш класс:

public class Boat : ITransportation
{
   public void TakeMeThere(string destination) // From ITransportation
   {
       Console.WriteLine("Going to " + destination);
   }
}

Что вы здесь говорите, так это то, что мой класс Лодка сделает все Транспорт сказал мне тоже.

А потом, когда вы хотите сделать программное обеспечение для транспортной компании. Вы могли бы иметь метод

Void ProvideServiceForClient(ITransportation transportationMethod, string whereTheyWantToGo)
{
      transportationMethod.TakeMeThere(whereTheyWantToGo); // Cause ITransportation has this method
}

Так что не имеет значения, какой вид транспорта они хотят, потому что мы знаем, что он может TakeMeThere

0 голосов
/ 02 февраля 2016

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

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

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

Пример:

Сначала нанесите слой приложения. Логика уровня 1, интерфейс уровня 2, внедрение зависимостей уровня 3. (У каждого свой путь, это просто для галочки).

На уровне логики вы ссылаетесь на интерфейсы и уровень зависимостей, а затем, наконец, вы создаете логику, основанную только на интерфейсах сторонних объектов.

Вот и мы:

public IEmployee GetEmployee(string id)
{
    IEmployee emp = di.GetInstance<List<IEmployee>>().Where(e => e.Id == id).FirstOrDefault();

    emp?.LastAccessTimeStamp = DateTime.Now;

    return emp;
}

Обратите внимание выше, как мы используем di.GetInstance, чтобы получить объект из нашей зависимости. Наш код на этом уровне никогда не будет знать или заботиться об объекте Employee. Фактически, если это изменится в другом коде, это никогда не затронет нас здесь. Если интерфейс IEmployee изменится, возможно, нам придется внести изменения в код.

Дело в том, что IEmployee emp = никогда не знает, что такое настоящий объект, но знает интерфейс и как с ним работать. Имея это в виду, это когда вы хотите использовать интерфейс, а не объект, потому что мы никогда не знаем или не имеем доступа к объекту.

Это обобщено .. Надеюсь, это поможет.

0 голосов
/ 02 июля 2015

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

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

0 голосов
/ 28 января 2010

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

public interface Foo {

}

public class FooFactory {
    public static Foo getInstance() {
        if(os == 'Windows') return new WinFoo();
        else if(os == 'OS X') return new MacFoo();
        else return new GenricFoo();
    }
}

Ваш код, который использует фабрику, должен знать только о Foo, а не о какой-либо конкретной реализации.

0 голосов
/ 28 января 2010

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

 public class TestClass
    {
        static void Main()
        {
            IMyInterface ob1, obj2;
            ob1 = getIMyInterfaceObj();
            obj2 = getIMyInterfaceObj();
            Console.WriteLine(ob1.CallSomeMethod());
            Console.WriteLine(obj2.CallSomeMethod());
            Console.ReadLine();

        }

        private static bool isfirstTime = true;
        private static IMyInterface getIMyInterfaceObj()
        {
            if (isfirstTime)
            {
                isfirstTime = false;
                return new ImplementingClass1();
            }
            else
            {
                return new ImplementingClass2();
            }
        }
    }
    public class ImplementingClass1 : IMyInterface
    {
        public ImplementingClass1()
        {

        }


        #region IMyInterface Members

        public bool CallSomeMethod()
        {
            return true;
        }

        #endregion
    }

    public class ImplementingClass2 : IMyInterface
    {
        public ImplementingClass2()
        {

        }
        #region IMyInterface Members

        public bool CallSomeMethod()
        {
            return false;
        }

        #endregion
    }
    public interface IMyInterface
    {
        bool CallSomeMethod();

    }

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

0 голосов
/ 28 января 2010

Это фундаментальное понятие в объектно-ориентированном программировании - полиморфизм. ( википедии )

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...