2017-02-15 28 views
0

Я читал информацию о программировании интерфейсов, а не реализации. Одной областью, которую я не совсем понимаю, является то, как бороться с не-интерфейсами. Например, интерфейс IAnimal и класс Cat, который его реализует. Мои примеры приведены на C#, но я думаю, что он также должен применяться к другим языкам.Неинтерфейсные методы

public interface IAnimal 
{ 
    void Eat(); 

} 

    public class Cat : IAnimal 
    { 

    public Cat() 

    public void Eat() 
    { 
     //Do something 
    } 


    public string Meow() 
    { 
     return "meow"; 
    } 

} 

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

Main() 
{ 
    IAnimal cat = new Cat(); 
} 

Но это оставляет меня без доступа к моему методу мяу поскольку он не является частью интерфейса IAnimal. Должен ли я создавать другой интерфейс ICat, который реализует IAnimals и позволяет Cat реализовать его? И означает ли это, что все методы должны быть реализацией из интерфейса или абстрактного класса? Или я делаю что-то еще здесь неправильно.

Благодарим за помощь.

+0

Не могли бы вы добавить более общий метод для интерфейса, возможно, 'string speak()'.? Тогда какой бы класс не реализовал, он может иметь свое собственное сообщение. – tinstaafl

+0

А как насчет классной рыбы, которая вообще не может говорить? – Eric

+0

Тогда он может вернуть пустую строку. Или индикатор того, что звука нет. – tinstaafl

ответ

0

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

с унаследованным интерфейсом.

public interface IAnimal 
{ 
    void Eat(); 
} 

public interface ISpeakingAnimal : IAnimal 
{ 
    string Speak(); 
} 

public class Cat : ISpeakingAnimal 
{ 
    public Cat() 

    public void Eat() 
    { 
     //Do something 
    } 


    public string Speak() 
    { 
     return "meow"; 
    } 
} 

public class Fish : IAnimal 
{ 
    public Fish() 

    public void Eat() 
    { 
     //Do something 
    } 
} 

С 2-интерфейс декоратора

public interface IAnimal 
{ 
    void Eat(); 
} 

public interface ISpeakable 
{ 
    string Speak(); 
} 

public class Cat : IAnimal, ISpeakable 
{ 
    public Cat() 

    public void Eat() 
    { 
     //Do something 
    } 

    public string Speak() 
    { 
     return "meow"; 
    } 
} 

public class Fish : IAnimal 
{ 
    public Fish() 

    public void Eat() 
    { 
     //Do something 
    } 
} 

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

public class Cat : ISpeakingAnimal 
{ 
    public Cat() 

    public void Eat() 
    { 
     //Do something 
    } 


    string ISpeakingAnimal.Speak() 
    { 
     return Meow(); 
    } 

    public string Meow() 
    { 
     return "meow"; 
    } 
} 
+0

Существует ли общее правило о том, когда нужно реализовать несколько интерфейсов или привязать интерфейсы? – Eric

+0

Зависит от того, как вы планируете его использовать. Для вашего примера в вашем вопросе вы будете использовать переход. Если бы у вас был код типа 'IEnumerable MakeThemSpeak (IEnumerable <...> obj)' вы, вероятно, будете использовать 'ISpeakable', так что если бы у вас были вещи, которые могли бы говорить, но где не животное, оно могло бы его использовать (например, возможно, у вас тоже был« IRobot »). –

+0

Хорошо, и тогда вы утверждаете, что все методы должны быть реализованы из интерфейса где-нибудь? – Eric

0

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

В этом случае было бы более интересно, чтобы оставить свой метод Meow() более общим для других возможных классов, которые могли бы реализовать его:

public interface IAnimal 
{ 
    void Eat(); 
    void Speak(); 
} 

public class Cat : IAnimal 
{ 
    public void Eat() { } 

    public string Speak() 
    { 
     return "meow"; 
    } 
} 

public class Dog : IAnimal 
{ 
    public void Eat() { } 

    public string Speak() 
    { 
     return "au"; 
    } 
} 
1

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

IAnimal cat = new Cat(); 

оставляет Вас неспособными методы доступа в классе Cat, которые не IAnimal. Итак, почему это поощряется к тому, чтобы реализовать вещи таким образом?

Ответ прост: он очень легко может изменить код позже. Например, если у нас есть класс, который реализует собак IAnimal, как так:

public class Dog : IAnimal 
    { 
     // some methods 
    } 

, то мы можем очень легко заменить наш класс Cat с классом Dog, без необходимости вносить изменения в любой другой код.Другими слова, мы можем заменить:

IAnimal cat = new Cat(); 

с

IAnimal dog = new Dog(); 

без изменения любого другого кода во всей программе (кроме имен переменных). Это связано с тем, что определение Cat и Dog по отношению к IAnimal заставляет их использовать только методы, найденные в IAnimal, хотя они могут быть реализованы по-разному в Cat and Dog.

Конечно, если вы хотите использовать что-то конкретное только кошка или собака, вы должны определить класс в явном виде, как было упомянуто @Erick в своем ответе, например, так:

Cat cat = new Cat(); 

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

0

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

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

Например, я бы не стал определять IAnimal или ICat интерфейсов. Вероятно, я бы определил абстрактный класс Animal и только конкретный класс Cat.

Если по какой-то причине мне нужно принять живых существ в какой-то API, которые могли бы съесть я бы определить интерфейс, как это:

public interface IFeedable 
{ 
     void Feed(Food food); 
} 

и если живое существо может говорить:

public interface ITalkative 
{ 
    void Talk(Food food); 
} 

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

public abstract class Animal : ITalkative, IFeedable 
{ 
    public Animal(AudioPlayer audioPlayer) 
    { 
      AudioPlayer = audioPlayer; 
    } 

    private AudioPlayer AudioPlayer { get; } 

    public abstract void Feed(Food food); 

    public void Talk() 
    { 
      // Probably you would want to load an animal sound library 
      // here, and later pass the audio player with the sound library 
      // already loaded 
      OnTalk(AudioPlayer.LoadLibrary("animals")); 
    } 

    protected abstract void OnTalk(AudioLibrary audioLibrary); 
} 

public sealed class Cat : Animal 
{ 
     public Cat(AudioPlayer audioPlayer) : base(audioPlayer) 
     { 
     } 

     public override void Feed(Food food) 
     { 
      if(food is Vegetable) 
      { 
       throw new NotSupportedException("MeeEEEEooW (=O ò.ó)=O!!"); 
      } 
      else if(food is Meat) 
      { 
       // Proceed to eat this meat! 
      } 
     } 

     protected override void OnTalk(AudioLibrary audioLibrary) 
     { 
      audioLibrary.Play("sweet-cat"); 
     } 
} 

И если где-то вам нужно сделать объект говорить:

ITalkative talkative = some as ITalkative; 

if(talkative != null) 
{ 
    talkative.Talk(); 
} 

Или, если вам нужно кормить объект:

IFeedable feedable = some as IFeedable; 

if(feedable != null) 
{ 
    feedable.Feed(new Vegetable()); 
} 

Как вы можете видеть, вы не» t определять интерфейсы для всего, но только для тех вещей, которые вам нужно обрабатывать внутри некоторого API, и вам все равно, кто может делать какие-то действия и/или владеть некоторыми данными, но вы просто заботитесь о том, что объект может делать или подвергает определенные виды поведения и d ata соответственно.