非接口方法

时间:2017-02-15 19:13:31

标签: c# oop interface abstract-class

我一直在阅读有关接口而不是实现的编程。我不能正确理解的一个方面是如何处理非接口方法。例如,接口IAnimal和实现它的Cat类。我的例子是在C#中,但我认为它也适用于其他语言。

public interface IAnimal
{
    void Eat();

}

    public class Cat : IAnimal
    {

    public Cat()

    public void Eat()
    { 
         //Do something
    }


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

}

从我所读过的内容来看,似乎我应该尝试使用界面而不是cat实现,例如,

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

但这让我无法访问我的meow方法,因为它不是IAnimal接口的一部分。我是否应该创建另一个实现IAnimals的接口ICat并让Cat实现它?这是否意味着所有方法都应该是接口或抽象类的实现?或者我在这里做错了什么。

感谢您的帮助。

4 个答案:

答案 0 :(得分:1)

接口的要点是定义实现该接口的类的通用行为。你注意到像这样定义猫是正确的:

    IAnimal cat = new Cat();

使您无法访问Cat类中不在IAnimal中的方法。那么为什么鼓励以这种方式实施呢?

答案很简单:以后可以很容易地更改代码。例如,如果我们有一个实现IAnimal的Dog类,就像这样:

    public class Dog : IAnimal
    {
        // some methods
    }

然后我们可以很容易地用Dog类替换我们的Cat类,而不必更改任何其他代码。换句话说,我们可以取代:

    IAnimal cat = new Cat();

    IAnimal dog = new Dog();

无需更改整个程序中的任何其他代码(除变量名称外)。这是因为定义关于IAnimal的Cat和Dog迫使它们只使用在IAnimal中找到的方法,尽管它们可能在Cat和Dog中实现不同。

当然,如果您想使用仅针对Cat或Dog的特定内容,您必须明确定义该类,如@Erick在其答案中所述,如下所示:

    Cat cat = new Cat();

通常,您应该尝试在界面中尽可能多地定义常见行为,但在绝对必要时,只能显式地转换为某个类,如Cat或Dog。这使您的代码更加通用和可变。

答案 1 :(得分: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";
    }   
}

答案 2 :(得分: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
    }
}

使用第二个装饰器界面

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";
    }
}

答案 3 :(得分:0)

我对这一主题的两分钱是,你需要依赖抽象(即接口)而不是实现。

顺便说一句,这不是太过分了吗?无需为对象模型中的任何类定义接口。通常,如果需要接受满足给定合同的某些对象,则定义接口。

例如,我不会定义IAnimalICat接口。可能我会定义一个抽象类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());
}

正如您所看到的,您没有为所有内容定义接口,但仅针对您需要在某些API中处理的内容,而您并不关心谁可以执行某些操作和/或拥有某些操作数据,但你只关心对象可以分别做或暴露某些行为和数据。