我一直在阅读有关接口而不是实现的编程。我不能正确理解的一个方面是如何处理非接口方法。例如,接口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实现它?这是否意味着所有方法都应该是接口或抽象类的实现?或者我在这里做错了什么。
感谢您的帮助。
答案 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)
我对这一主题的两分钱是,你需要依赖抽象(即接口)而不是实现。
顺便说一句,这不是太过分了吗?无需为对象模型中的任何类定义接口。通常,如果需要接受满足给定合同的某些对象,则定义接口。例如,我不会定义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());
}
正如您所看到的,您没有为所有内容定义接口,但仅针对您需要在某些API中处理的内容,而您并不关心谁可以执行某些操作和/或拥有某些操作数据,但你只关心对象可以分别做或暴露某些行为和数据。