您所在的位置: 程序员家园 -> 家园博客 ->
 
在哪里摔倒
就在哪里自己爬起来

用户登录

查  找

最新评论

最新留言

常用网站

网易邮箱 GMAIL  

百度搜索 MSDN

霏凡软件 BT精品

影视帝国 射 手 网

电驴下载 全 库 网

友情连接

茄菲的窝 冰冰博客

枫叶飘零 玫  瑰

ACEN 云 豹 子

统  计



不要把接口当妈妈,要什么都可以
狼子 发表于 2008-5-3 16:45:00 阅读全文 | 回复(1) | 引用通告 | 编辑

“不要把接口当妈妈,要什么都可以”这是一个五岁的小姑娘说的话

我一直想不懂接口有什么用,现在我想明白了,因为我把接口当妈妈了,所以当接口不可以满足我想到的一些要求的时候,我就觉得很奇怪,我把接口的作用全都推翻了

嗯,可以先看这个的:user1/9/archives/2007/3877.html,这是大山峰给我解释接口的记录

大山峰的解释后,我觉得我还是一直想不懂接口,我不明白为什么要有接口,我觉得有类就够了,为什么还要弄一个接口出来,这么麻烦干什么呢?当我研究风讯的时候,我发现风讯整个就是使用接口的,我觉得很奇怪,他们为什么要一层套着一层呢?为什么不直接写公共类,还要写接口呢?

然后呢,看这一段,这是2008年4月29日下午,书生给我解释接口时的对话,和书生的对话后,我明白接口就是一个规定,嗯,就是给一堆东西,做出一个规定,所有继承这个接口的类,都要符合这个规定,因为rules are rules

狼子()  14:54:23
我不是很搞得明白接口的,因为我老想不懂接口有什么用,接口只是定义方法,只是定义,又不给出方法里的代码,使用接口的类,就变成要把接口里的类的方法的代码全部写出来了

比如说一个接口里有CallMother()这样子的方法,然后呢,有一个类用到这个接口,那这个类里就要给出CallMother() { //给妈妈打电话的全部代码 }

有什么类用到这个接口,什么类就要自己去重新搞它,有什么好处呢?

逍遥书生()  14:56:28
这个也有好处的

逍遥书生()  14:59:05
1.客户端用户不知道也不必知道组件内部的具体实现,只需使用组件提供的接口就可以了!这样既方便了客户端用户,又可防止客户端的误操作!  
  2.可以用不同的语言编写!!  
  3.接口一旦定义,就是一层不变的,这样便于组件的版本升级!   

逍遥书生()  15:00:32
使用接口可以使程序更加清晰和条理化

狼子()  15:05:01
1、客户端用户如果要用接口,还要自己写接口里每个方法的实现代码,比如这样子的接口:
interface IAdd
{
  int AddNumber(int a, int b);
}
A用户可以这样子定义:
public class AddNumber : IAdd
{
  public AddNumber(int a, int b) { return a + b; }
}
B用户可以这样子定义:
public class AddNumber : IAdd
{
  public AddNumber(int a, int b) { return a - b; }
}
A、B用户都实现了接口里的方法,就是B用户肯定是错误的方法,这个不叫误操作,这个叫做大bug呢

2、可以用不同的语言编写,这个在.net里,本来就可以用不同的语言编写啊,在同一个网站里,在同一个项目里,都可以又用VB.NET又用C#的,只要最后编译过了就行

3、接口只是定义了方法,定义方法的名称、参数、返回值,就是,里面的东西什么都不定义,想怎么改就怎么改,为什么还叫一层不变呢?就是方法名称这一层不变吗?

逍遥书生()  15:06:50
哈哈

狼子()  15:07:42
我知道接口是好东西,不是好东西,不会这么多人用,就是,我想不懂他为什么好,他就像一件衣服,每个人都可以穿。。。

狼子()  15:10:08
一件衣服,每个人都可以穿,就是,有的人穿着刚刚好,有的人穿着太大了,有的人穿着太小了,就好像实现方法的代码都不相同一样子,那做这件衣服干什么呢?为什么不直接给每个人一件衣服呢?

逍遥书生()  15:10:56
我想想怎么说好些呢,比如有人这个类,吃饭是个接口,中国人是人的子类,实现的吃饭的接口是吃中餐,外国人实现的时吃西餐,虽然吃的方法不一样,但都要吃饭这个事先要定义好,不然如果你有个子类不吃饭那就是个怪人了

逍遥书生()  15:11:41
如果这个类指定了必须实现吃饭这个接口的话就不必担心弄出不吃饭的人来了

狼子()  15:12:03
每个人都要吃饭,先定义了这个方法,规定每个人都要吃饭,吃什么饭,就自己定义?

逍遥书生()  15:12:30
是的,不同的子类吃饭的方法不一样

狼子()  15:12:42
我有点明白,我在想

逍遥书生()  15:12:56
但大家都必须吃饭

逍遥书生()  15:16:34
我说的不同国家是不同的子类

逍遥书生()  15:17:51
我的意思是,中国人、外国人这些类都要实现吃饭这个接口

逍遥书生()  15:18:29
这样就可以避免弄出不吃饭的人来

逍遥书生()  15:20:29
不过我觉得这种东西也不是非用不可的,尤其是小项目

狼子()  15:21:50
用接口定义好,每个人都要吃饭
interface IHuman { void Dine(); void Dressing(); void Sleep(); }

然后呢,给出好多个类,每个类都要实现这些方法
public class Chinese : IHuman
{
  public void Dine() { return Chinese food; }
  public void Dressing() { if(boy) { return pants; } else { return skirt; } }
  public void Sleep() { return bed; }
}
public class English : IHuman
{
  public void Dine() { return English food; }
  public void Dressing() { if(boy) { return pants; } else { return skirt; } }
  public void Sleep() { return bed; }
}
看这两个类,对吃饭Dine这个方法,是不同的,所以可以返回不同的方法,接口定义下了是必须要有这个方法,所以必须要吃饭,那穿衣和睡觉呢?两个类,都是完全一样子的方法啊,这样子,如果每个国家的人都要定义一个类,那这样子对dressing和sleep有什么好处呢?

狼子()  15:25:26
书生。。。你说的吃饭我懂了,必须吃饭,就是一个规定,大家都要吃饭,就是,这个规格,有时候是全部一样子的,就是,他又是必须的规定,就像穿衣服和睡觉一样子

狼子()  15:26:30
对全部一样子的规定,接口有什么好处呢?每个类都要重新实现他。。。

逍遥书生()  15:29:47
我想想怎么说呢

逍遥书生()  15:36:00
比如这中国人、英国人类是你定义的,别人对他的实例进行操作时,只要知道这个类是实现了吃饭这个接口的,在要吃饭时直接调用吃饭方法就可以了,不要担心有什么问题

狼子()  15:36:36
那是类啊

狼子()  15:38:08
在要吃饭的时候,是这样子吃的:
Chinese c = new Chinese();
c.Dine();
对不对?有没有接口,不知道,只要知道Chinese类里有Dine方法

狼子()  15:38:43
嗯,我想啊,刚才应该再加上一个die方法的

逍遥书生()  15:43:10
哈哈,这个只能自已慢慢理会

狼子()  15:44:20
我都理会这么久了。。。我就是搞不懂接口干什么用

狼子()  15:44:39
多麻烦啊,还要搞一个接口出来

看啊,sleep这样子的方法,有可能会是不同的类,继承同一个接口,然后呢,实现的代码又是完全一样子,看上去好像我们要重复为同一个方法写很多次代码一样子,我们因为接口,在重复劳动。。。我一直就是因为这样子的原因,觉得接口不好

五岁的小姑娘,多聪明啊,我就是吃饭的时候和她妈妈说这个我想不懂的问题,她的妈妈也不懂计算机,就是,我想不懂的问题,我需要别人和我讨论,懂不懂计算机,懂不懂编程没有关系,说别的也可以,有人和我说,我就可以继续想,比如说,反驳别人看着好像不对的说法,很多时候这种办法可以帮助我想懂好多问题的

今天,小姑娘说:“不要把接口当妈妈,要什么都可以”

听到这句话的时候,我很生气,接口不是妈妈,傻瓜都知道,然后呢,我发不出脾气了,因为我知道小姑娘说对了。。。

接口的作用,就是书生说的,定一个规定,所有继承这个接口的类,都必须遵守这个规定,实现接口里定义的所有方法,方法名称、参数名称和多少,都不可以修改,必须全部实现,所以这些类,就全部都被规定了,这个就是接口的作用了,接口的作用就是这个,不会再多了,接口不是妈妈,不是我想要接口实现什么,接口就会满足我什么的

像上面提到的dressing和sleep两个方法,在Chinese和English两个类里面,他们完全相同,所以代码就变成重复了,在这种情况下,我可以写一个基类,这个基类继承自IHuman接口,然后呢,这个类里的Dine方法是虚拟方法,然后呢,Chinese和English两个类再继承这个基类,只需要override dine方法就可以满足我的这个不写重复代码的要求了

这个,是类的作用,不是接口的作用

下面给出我的测试代码

using System;

namespace studyInterface
{
    //定义接口,在接口里,只声明方法,不包含方法的内容块
    interface ICreature
    {
        void Dine();    //吃饭
        void Sleep();   //睡觉
        void Die();     //死亡
    }
   
    //定义Creature类,声明这个类继承自ICreature,这个是基类,里面实现ICreature中定义的三个方法,设置这三个方法为虚拟方法,允许子类覆盖
    public class Creature : ICreature
    {
        //定义一个类成员变量,记录生物的名称或人的名字
        protected string name = "";

        //实现继承IHuman接口的三个方法
        public virtual void Dine()
        {
            Console.WriteLine("{0} eats nothing today.", name);
        }
        public virtual void Sleep()
        {
            Console.WriteLine("{0} sleeps most of the night.", name);
        }
        public virtual void Die()
        {
            Console.WriteLine("{0} die.", name);
        }
    }

    //定义Human类,声明这个类继承自Creature,添加一个Dressing方法
    public class Human : Creature
    {
        //添加一个成员变量,记录性别
        protected string sex = "";

        //添加Dressing(穿衣)方法
        public void Dressing()
        {
            string dress = "nightgown";
            switch (dress)
            {
                case "boy":
                    dress = "pants";
                    break;
                case "girl":
                    dress = "skirt";
                    break;
            }
            if (sex.Equals(""))
            {
                Console.WriteLine("{0} wears a {1}.", name, dress);
            }
            else
            {
                Console.WriteLine("{0} is a {1} wearing the {2}.", name, sex, dress);
            }
        }
    }

    //定义Animal类,声明这个类也继承自Creature,重写Dine方法
    public class Animal : Creature
    {
        //添加一个成员变量,记录是不是食肉动物
        protected bool isCarnivore;

        //重写Creature类的Dine(吃饭)方法
        public override void Dine()
        {
            if (isCarnivore)
            {
                Console.WriteLine("{0} has meat today.", name);
            }
            else
            {
                Console.WriteLine("{0} has grass today.", name);
            }
        }
    }

    //定义Chinese类,声明这个类继承自Human
    public class Chinese : Human
    {
        //构造函数
        public Chinese(string personName, string personSex)
        {
            name = personName;
            sex = personSex;
        }
    }

    //定义English类,声明这个类继承自Human
    public class English : Human
    {
        //加一个成员变量,设置是不是Scottie
        protected bool isScottie = false;

        //构造函数
        public English(string personName, string personSex, bool pIsScottie)
        {
            name = personName;
            sex = personSex;
            isScottie = pIsScottie;
        }

        //重写父类Human的Dressing方法
        new public void Dressing()
        {
            if (isScottie)
            {
                Console.WriteLine("{0} is a Scottie wearing a kilt.", name);
            }
            else
            {
                Console.WriteLine("{0} wears a robe.", name);
            }
        }
    }

    //定义Hen类
    public class Hen : Animal
    {
        public Hen()
        {
            name = "Hen";
            isCarnivore = false;
        }
        //重写Dine方法
        public override void Dine()
        {
            Console.WriteLine("{0} pecks the corn.", name);
        }
    }

    //定义Tiger类
    public class Tiger : Animal
    {
        public Tiger()
        {
            name = "Tiger";
            isCarnivore = true;
        }

        //重写Dine方法
        public override void Dine()
        {
            Console.WriteLine("{0} preys on bunny.", name);
        }
    }

    //定义Owl类
    public class Owl : Animal
    {
        public Owl()
        {
            name = "Owl";
            isCarnivore = true;
        }
       
        //重写Dine方法
        public override void Dine()
        {
            Console.WriteLine("{0} catchs a mice.", name);
        }

        //重写Sleep方法
        public override void Sleep()
        {
            Console.WriteLine("{0} sleeps most of the day.", name);
        }
    }

    public class TestInterface
    {
        public static int Main()
        {           
            Chinese c = new Chinese("Lanlan", "girl");
            c.Dressing();
            c.Dine();
            c.Sleep();
            Console.WriteLine("--------------------");

            English e = new English("Peter", "boy", true);
            e.Dressing();
            e.Dine();
            e.Sleep();
            e.Die();
            Console.WriteLine("--------------------");

            Hen h = new Hen();
            h.Dine();
            h.Sleep();
            h.Die();
            Console.WriteLine("--------------------");

            Tiger t = new Tiger();
            t.Dine();
            t.Sleep();
            t.Die();
            Console.WriteLine("--------------------");

            Owl o = new Owl();
            o.Dine();
            o.Sleep();
            o.Die();

            return 0;
        }
    }
}

Re:不要把接口当妈妈,要什么都可以
mountain315发表评论于2008-5-8 10:17:00 个人主页 | 引用 | 返回 | 删除 | 回复

类的作用不只是一个规定,就像书生一开始和我说的那三点一样子,因为我是开发的人,我一直对着源代码,我没有想过dll的问题,所以我想不懂

这个是刚才九婆婆说的:

hongjuan  9:56:24
这个就是和写dll一样的啊,调用dll的人并不需要知道那些功能是如何实现的,只需要按照怎么样的规则去调用就可以

就是说用户是不知道类是怎么实现的,他们只知道接口,他们是靠接口里定义的方法去调用的,这些用户,不是像我这种对着源代码自己写接口和类的用户,是那些用我给定的接口,调用我写的代码的用户

九婆婆还提到了抽象类,说“保护底层代码不被非法修改”和“规范公开接口”这些作用,抽象类也可以实现,就是,我还不知道抽象类。。。

发表评论:

    昵称:
    密码:
    主页:
    标题:
Powered by Oblog.