关于c#:在决定接口与抽象类时,正确的实现是什么?

What would be the correct implementation while deciding over interfaces vs abstract classes?

本问题已经有最佳答案,请猛点这里访问。

我最近遇到了一个与类创建/建模相关的问题。

把动物王国作为阶级模型。使用类创建各种表示为虚拟动物园的对象。在这个虚拟动物园中添加20只动物(在程序的主要方法中),让每只动物都发出声音。这不应该是20种不同的物种)。

我考虑了这个问题,决定使用抽象类动物而不是界面。然后我又增加了两类,鸟类,哺乳动物,它们是由动物遗传的。

我的实施

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  public abstract class Animal{

      abstract Sound MakeSound();
    }

    public class Bird : Animal
    {
       private Sound _sound;
       public Bird(Sound sound){
       _sound = sound;
    }
    public Sound MakeSound(){
          return _sound;
       }
    }
//same as above with Mammals

public class Program
{
  Animal crow = new Bird("Crow sound");
  Console.WriteLine(crow.MakeSound());

 Animal dog = new Mammal("Dog sound");
  Console.WriteLine(dog.MakeSound());

// and so on with other animals
}

我的问题是-

  • 我的实现有什么问题?
  • 设计动物王国的正确方法是什么?OOPS概念?
  • 在什么场景中,我们使用抽象类上的接口,反之亦然。(以现实世界为例)
  • 请推荐一些网上的资料,我可以在这些问题上改进。谢谢。


    首先,重要的是要认识到,尽管"在一个阶级层次中模拟动物王国"是一个常见的初学者练习,并且经常用于示例中——我总是在示例中使用动物、哺乳动物、长颈鹿、老虎等——使用OO技术解决这不是一个现实的问题。它的目的只是让您通过思考一个您已经很好理解的领域来思考OO编程中的概念。

    真正拥有管理动物库存软件的动物园不会建立这样的等级体系,因为它们的关注点实际上并不包括哺乳动物和鸟类的共同点。尽管动物王国的类比对于实现OO是有用的,但重要的是不要放弃这样一种信念,即现实世界层次中存在的每一个特性都必须在类层次中建模。

    所以,也就是说,我其余的评论都是假设你真的想把动物王国作为一种练习来模拟。

    第二,实现的基本问题是层次结构不够深或者太深。问题是哺乳动物和鸟类应该是抽象的,因为世界上没有什么东西只是哺乳动物或鸟类。你想要的是一种抽象类的鸟,它可以扩展动物,然后是一种具体的(可能是密封的!)延伸鸟的类乌鸦。

    接下来要问的问题是:我真的需要哺乳动物和鸟类的水平吗?它们对我的程序有用吗?我有没有一种方法可以带走任何哺乳动物,但没有蜥蜴?如果它没用,就把它消灭,直接从动物到乌鸦。

    第三,乌鸦发出的声音是"caw caw",而不是"crow sound"。-)

    第四,回答你最好的问题:当你有几个不相关的东西"可以做"同一件事但有不同的实现时,你通常使用一个接口,并且你使用一个抽象类在有"是一种"关系的类之间共享实现细节。

    制造一个声音是很多事情都可以做的事情,它们彼此之间是不相关的。鸟和钢琴不是同一种东西,它们有不同的机械装置,但它们都能发出声音。所以发出声音应该用一个接口来表示。鸟是一种动物,可能有共同的功能,所有的动物都是专门由鸟类。

    简而言之:鸟是一种动物,所以它应该是一个子类。一只鸟可以发出声音,很多其他东西也可以,所以发出声音应该是一个接口。


    您希望使用接口的原因之一是C不支持多重继承。

    一般来说,我想把接口看作是一种能力或特性,而不是模型。

    类似:

    1
    2
    3
    4
    5
    6
    7
    8
    9
        public interface ISwimable
        {
             int SwimmingSpeed { get; set; }
        }

        public interface IWalkable
        {
            int RunningSpeed { get; set; }
        }

    现在,如果我有一只生活在水中的动物,我希望它能实现ISwimable,如果我有一只可以行走的动物,它的类应该实现Iwalkable,如果它能两者都实现,它将实现两者。