疯牛涕淌是从零二年夏天开始玩魔兽的,到现在也算只老鸟了吧。你是不是也是个魔兽迷呀?不过话说回来,玩物可不能丧志的,不知你在玩过这些游戏的时候,是不是和我一样也思考些别的东西,比如软件的设计思想等等什么的。呵呵,别骂我变态
好好好言归正传(故意咳嗽两下)
!领会面向对象,关键是这三个基本的概念:封装、继承和多态性。我按照顺序分别讲解一下。封装是什么呢?很简单,在你写代码的时候,你一定有过把一个变量声明为Private的经历吧?你不希望外部世界来污染它——这就是封装。在一个类中,它的内部变量(你也可以直观地把它们认为是属性)默认下是隐藏于外部世界的。如果你要操纵一个类,那么,请直接告诉他你想让它做些什么吧——至于它是怎么做到的,这个你没权利了解的。
呼呼,你在玩魔兽的时候,英雄的那些属性,譬如生命值、魔法值、攻击力值等,其实就是被封装在每个英雄的类里的。那我们为什么可以读取这些属性呢?那是因为这些类提供给了我们读取属性的接口。譬如你想读取或设置月之女祭司的生命值,你其实在不知不觉中经历了下面几个步骤的。你先是对月之女祭司说:“月之女祭司,我想看下你的生命力的值,可否?”她说:“这个嘛,我时刻都把我当前的生命力的值公布在我的状态栏上,你自己看去吧。至于我是怎么把我的这些值公布出来的,你无权知道。”然后忘形的你竟然得寸进尺,想从状态栏上直接修改她的生命力值。她会十分气恼地说:“但是我不提供这样的服务!你得让我喝月井的水才行呀!”哦~~~喝月亮井的水便是另一个和生命值挂了钩的方法呀,你可以通过这个接口修改生命力值了。这样的接口起到了约束使用者的目的,避免了数据被非法污染,实现了封装的初衷。
象上面的读取属性的方法也被叫做“只读方法”,同样地也有“只写方法”,一样样的道理,我懒得赘述了。需要说的是,并不是所有的内部属性都拥有通向外界的接口。记住,类的设计总是要让它在它的使用者看起来更简单,因此如果某个类的编写者认为其中某个数据成员没有必要被使用这个类的人感知到它的存在,那么如果那天他没有喝太多酒的话,他就不会对那个数据提供任何相应的接口。这样,这个属性就彻底地被封装起来了。
当然没有人会阻止你把变量声明成Public,但是也绝没有人推荐你这么做,所以这样声明之前请你确信这样是必要的。你可以试想一下,如果月之女祭司把控制她的生命力值的权利完全地公诸于众,那么游戏还有什么公平性可言呢?
“总款哦……”你茅厕顿开,“类就是这么一回事呀!把它的数据隐藏,而通过它公开的方法来实现其和类的使用者的互动。魔兽中那么多英雄,每个族四个,加上六个中立英雄,二十二个英雄就是二十二个类哈!”那我会摸着你的头说:“对,你真是可以这么认为的。Hmmm,都有四种魔法,都有生命值、魔法值、最大攻击力值、最小攻击力值、防御力值,etc。那么二十二个英雄,我们都可以慢慢地写,没问题……”
这时你突然用力推开了我的手:“且慢!既然二十二个类有这么多公用的属性和方法,那你干屌不试着直接写出一个抽象的英雄类呢?”我说你狂有思想的,因为这就是当初引进继承的滥觞。不单单魔兽中的英雄如是,你细细观察一下,生活中和机器世界里也充斥着这样的例子。如果不利用它们的派生继承的关系,而冲动地将每个类都设计成一个独立的类,那么你将要重复写多少行代码?这么一想来似乎有点恐怖吧?所以我们要继承,因为这样的机制在很大程度上提高了我们开发软件的效率。
让我们把话题再拉回到我们的前面提到的英雄抽象类上。我猜你不太敢想象这样的类被创建成实例会是什么样是么?呵呵,反正我是不敢想象的。因为我一试图这么做,我头脑中总会浮现出一只脊椎动物的受精卵,红红软软的一坨,鬼知道它成熟后会是什么屌样,反正好恶的样子。
请你在这里稍停顿思考一下……12秒钟吧……
如果你够聪明的话,你一定会追问我:“那么,既然是个不愿意被实现的抽象基类,那么这个类里面的方法要怎么写?比如说UseUltimateSkill……”嗯,问得好!既然我们不愿意抽象类被创建成实例,那么很简单,我们也不必费神去写代码了,但是我们在这个类的方法前签个单方协议——我们姑且称之为“MustInherit”协议吧。协议正文是这么写的:“你要继承我是吗?没问题!但是,你必须自己填充你对我的这个方法的实现。否则,你就别指望继承我啦!”
于是每个英雄便急着各显其神通了。恶魔猎手说:“我最想耍流氓,就让我来个流氓大变身好了!”大法师在一旁诡异地哼了一声:“你猛,老子俺惹不起躲得起。俺就瞬间转移吧嘿嘿。”死亡骑士也不甘示弱:“我最高尚,我要让别人实现起死回生!”这可把老牛酋长乐坏了:“这年头高尚早不时髦了,看我让我自己起死回生的本事,还全自动的呢!”……于是二十二个英雄就这样拥有了自己的魔法——一个方法名,真真是千姿百态啊!
这时你呆滞地抹去嘴角的口水问道:“哦,涕淌兄,这不会就是多态性吧?”
我说废话小子哈哈。