×

Loading...

厕所是如何建成的(一):胡侃面向对象基础

本文发表在 rolia.net 枫下论坛厕所是如何建成的(一):胡侃面向对象基础

叶雨


说真的,一直想给小朋友们写本教科书。因为我自己在小时候看见教科书特别害怕:不容易看懂。我感觉是似乎写教科书的老学究们觉得一定要用晦涩深奥的语言来写抖书包才算是有水平,要是通俗易懂,那就表示作者的水平低下,粗俗。

所以今天想跟立志入门IT的筒子们侃一下当下编程流行的面向对象的一些概念。

面向对象的概念在我们的现实生活中也是无处不在,所以今儿咱们不谈电脑,改拉家常。

那么既然说面向对象的概念无处不在,就举个例子吧:用我们如何解决“小便”这个问题,来谈谈面向对象的一些概念。

你的用户需求是这样的:我要小便,急。

为了解决这个艰巨的问题,叶雨来给你上堂课。我先问个问题:“你知道小便的方法有多少种吗?”(估计我会被茴香豆砸死)

好了,你首先要搞清楚,你小便需要什么?啥?厕所啊!你先忍着小便,听叶雨讲讲如何盖这个厕所。

我们要定义一下,什么是厕所。首先,厕所是个厕所,但同时它又不是个厕所。晕了吧?嗬嗬,这就是我要的效果。你要在挨踢(IT)界混,你要学会的第一件事情,就是“纸上谈兵”。

“纸上谈兵”这个事情,做得不好就是:“瞎掰”,做得好就叫“抽象设计”(Abstract)。所以具有“抽象”能力的挨踢人看到的厕所就不是厕所,而是能把一些共性抽取出来而形成一个“类”。

“类”(Class) 在这里就是建造厕所的蓝图。而“对象”(Object)就是用“厕所”的蓝图建造出来的实际“厕所”。现在懂了吧,为啥厕所(类)是个厕所(Class,蓝图),但同时它又不是个“厕所”(Object,实际建成的厕所实体)。

那么我们从厕所里除了能抽取粪便,还能抽取些什么出来?

至少我们有:马桶。这是构成所有厕所(中国旅游区的厕所除外)的基本要素。

好了,所以在我们的蓝图上,我们有:马桶。为了好听起见,这些东西称之为“属性”(Attribute)。当然,针对马桶可以有“解小便”这个动作,我们把这个动作称之为“方法”(Method)。好了,

现在出现一个面向对象的最重要的概念之一,就是“封装”(Encapsulation)。说白了就是“自成一体”。那么在“厕所”这个“类”里,封装了一个“属性”:马桶;也封装了一个“方法”:解小便。

“封装”真的太重要了。可以说没有它就不可能存在真正的“面向对象”。这么说吧:商店里在卖马桶,你能跑进去对着马桶就小便吗?最起码你得拿个什么把四周围遮一下吧?你看,技巧就在这里。就这么“遮”一下,你就把马桶给“封装”成了一个“厕所”,从而可以自欺欺人地在里面舒畅。懂了吧?要是实在不懂就记住祖国著名诗人赵丽华的诗:

“我坚决不能容忍
那些
在公共场所
随地大小便
的人。”

真搞不懂为啥这么多无聊的人在攻击赵丽华。人家小姑娘用一首小丝就道破了“封装”的重要性,难怪是国宝级的诗人,我们要好好保护才是。

说了这么多,忘了问一个重要问题,您要男厕所还是女厕所啊?完了吧,原以为你能“封装个”厕所赶紧让你解决问题,现在连男女厕所都没弄清!

还好,面向对象里面有“继承”(inheritance)功能。男厕所、女厕所,不都是厕所吗?所以它们能继承厕所“类”。因为男厕所和女厕所都继承了“厕所”,所以“厕所”成了父类(Super Class),男厕所个女厕所成了子类(Sub Class)。

“继承”是面向对象的第二个重要概念。

好了,既然继承了父类,我们盖男厕所的时候就已经具备了父类(厕所)的所有属性和方法。不过需要注意的是,在父类里面,“解小便”这个方法只被解释成“坐着上”,没有考虑到有些变态男人也能“站着上”。于是乎男人为了自己的自私目的,重新定义男厕所里的“解小便”。这个方法的具体代码就是“坐着上还是站着上,看我心情如何”。女厕所也继承了父类“厕所”的所有属性,她们老老实实地没有修改父类的“解小便”的具体代码,那就是维持“坐着上”(别跟我抬杠说女人不一定要坐着,你就可怜可怜男人吧。现代社会女人已经无所不能,男人只剩下“站着上”这个最后专利了…..)

在子类各自解释不同的父类方法时,我们发现了第三个重要概念:“多态性”(Polymorphism)。

多态性有几种:男厕所类对厕所父类里面的“解小便”有了不同的诠释。这个不同的诠释是由于重写父类的方法而得来的,所以这种多态性叫做基于重写继承(inheritance)的多态,也叫做“override”。

好了,喜欢抬杠的人就发话了:男厕所不是还有尿兜吗?

好了,厕所父类定义了一个解小便的规格,那就是: 解小便(马桶 某马桶,小便者 某人)。
那么在男厕所里面,除了我们有马桶这个属性,另外我们还有“尿兜”这个新属性。
要注意,在“继承”里面,我们强调了继承父类和沿用/复用的特性。但是由于继承产生的子类理所当然也会有自己特有的东西,例如这个男厕所里的尿兜。

男人们因为父类的马桶,而有了自己对使用马桶的诠释,然而还没有对如何使用尿兜的诠释。好在男人们自己发明了一个名称相同,但是参数不同的解小便新规格:解小便(尿兜 某尿兜,小便者 某人), 而其具体实现的方法就是“站着上”。

好了,现在在男厕所里,男人们可以有两个小便的方法可以选择:
解小便(马桶 某马桶,小便者 某人), 实现方法:“坐着上还是站着上,看我心情如何”。
或者:
解小便(尿兜 某尿兜,小便者 某人),实现方法:“站着上”。

这就出现了第二个多态性,叫做同一个类里面基于同名方法的不同签名的多态性,还是老外简单,把这个叫“overload”。要注意override跟overload的区别。

男人可以选择站着或者坐着小便,一会儿override,一会儿overload,不如就叫“多态男”,或者只呼“变态男”算了!

总结一下:所谓面向对象三大特性就是:封装,继承,多态(变态)。

好啦,我们伟大的男厕所建成了!你给了我几百万,我给你盖了个是富丽堂皇、镶金镀银的厕所,不错不错!

不过我忘了告诉你,你还没有对你厕所里的东西定义权限。啥权限啊?就是私有还有共有呗!为啥啊?难道有人跑到厕所里偷马桶盖不成?嘿你真新鲜!连大街上的井葫芦盖都有人偷了去卖钱,偷你个镶金马桶盖还不是小菜?

那咋办?把你的男厕所里面的东西定义成私有啊,这样别人就偷不走了!好,就这么办!让我们来看看男厕所里面都有啥:
两样东西:马桶、尿兜;两个方法:解小便(马桶 某马桶,小便者 某人)、解小便(尿兜 某尿兜,小便者 某人)

我们给这些个东西都上锁,都弄成“私有”,这就保险了!原来面向对象还能保护私有财产,真是个好东西啊!好了,马桶有了,尿兜有了,使用马桶和尿兜的小便方法也有了,锁也上好了,齐了!搞了这么多事儿,您尿憋急了吧?那就赶紧上厕所啊!咋了?还不进厕所?

现在才发现个重要问题:厕所没门儿!

好嘛!建了个富丽堂皇的私有化安全厕所,小偷是进不去了,您自个儿也进不去了!

啥叫高科技垃圾?这就叫高科技垃圾!最后你逼急了,随便在您几百万的厕所外面找个墙角旮旯解决拉倒,不受这洋罪!

好了,等你花了几百万盖了个无门高级厕所,然后你在厕所的墙脚用原始方法解决了以后,我再告诉你:你再给我一百万,让我做第二期工程吧,我来给你装个门,厕所就能用了。那你肯定会骂:干吗不早说?你傻啊?你不知道挨踢界里面,所有的第一期工程都是没法用的垃圾,然后程序员再向业务部门要钱搞第二期、第三期……把这个高科技垃圾维持下去,不这么干我们喝西北风去啊?

好了,除了“私有”(Private)这个权限,还有“公有”(public)和“保护”(protected/friendly)等权限(具体到不同的语言有些些微差别)。其实这三个权限属于前面“封装”的范畴。现在讲讲它们的区别。私有(private)就是完全属于“物主”。产生了一个对象,对象本身就是“物主”。那么private就是只能物主关在自己的房间里自己用。所以你其实可以使用没有门的高级厕所,前提是要把你也永远关在厕所里面。
“公有”就是顾名思义了。如果是要建公共厕所,这个权限是不能少的。那么“保护”呢?保护的权限相当于家庭厕所。三类人可以用这个厕所:物主(也就是被关在厕所的那位)、物主的子女们(继承了该类的子类们)、同屋的人(在同一个包里的类)。

那么我们该如何应用这些权限呢?有一个趋势,就是所谓的“高内聚,低耦合”(highly cohesive, loosely coupled)。叶雨一下子变得这么学究,你是不是该晕了?好了啦,所谓高内聚就是自己的东西要保管好,低耦合就是“能不上套就不上套”。那么具体到“男厕所”这个类,什么东西需要高内聚的?马桶,尿兜。我们要确保这两个东西保管好,所以对马桶、尿兜实行“私有”。刚才说过,除非把你关在厕所里不出来,否则你不能使用私有的马桶跟尿兜。好了,技巧来了:你是不能直接使用私有的马桶跟尿兜,但是你别忘了还有两个定义好的方法啊:两个方法:解小便(马桶 某马桶,小便者 某人)、解小便(尿兜 某尿兜,小便者 某人)。
好了,因为小便方法是男厕所类里面的成员,所以理所当然这两个方法能够直接访问到私有的马桶跟尿兜。然后我们把这两个方法弄成共有的(public)不就行了吗?这个方法真是天才!一方面我们保证了马桶跟尿兜谁也偷不走,一方面我们可以开放公共厕所了,让大家一起来小便。问题解决啦!

好了,造价高昂的公共厕所正式营业了。你坐在厕所门口收钱,开始觉得回报的时候到了。但是好景不长,里面开始有人嚷嚷他们不能使用马桶!咦?我们不是已经定义了一个解小便的方法了来让大家使用马桶了吗?

一问之下,原来有人想对着马桶解大便,而你只提供了解小便的方法,而没有大便的方法!那你要问了,如果别人知道如何对厕所里的马桶解大便,为啥还要我们提供解大便的方法啊?这是因为我们已经把马桶“私有”了,所以除了厕所内部定义的方法,否则外部一切的动作都不能直接作用在我们的马桶上。也就是说,你想大便可以,但是要按我们的方法来!

你看,辛辛苦苦盖了这么好的厕所,只能小便不能大便!顾客们吵着要退钱,你没办法,找挨踢去了,说能不能加个“大便”的方法。那当然欢迎之至了!第三期大便工程,再加一百万!

好了,基本调侃了几个面向对象的概念。还有许许多多具体的细节没有提及。本文毫无章法,纯粹瞎聊,充其量只能引发部分筒子们的学习兴趣。如果真的要有系统地学习这部分知识,还请回去找老学究们的书好了。对本文有任何补充指正,欢迎之至,免费!嗬嗬。

========
《厕所是如何建成的》科普系列文会陆续写作,针对非IT人士,入门认知。

--叶雨更多精彩文章及讨论,请光临枫下论坛 rolia.net
Sign in and Reply
Modify
Report

Replies, comments and Discussions:

  • 工作学习 / 学科技术讨论 / 厕所是如何建成的(一):胡侃面向对象基础
    • 一点异议:
      解小便因该封装在小便的人里面。接小便才是封装到厕所里面。
      • 同意。这样的话做个修改: 某人.小便( 某男厕所.get马桶( ) ) 。这样更加符合现实一些。谢谢轮胎。
        • 应该小便者狂喊一声:小便(事件);厕所就马桶移到面前接着(响应事件);小便者完了再喊一声滚,厕所就把马桶藏起来。
        • 你怎么知道某人是男的呢?如果某厕所满了呢?你准备怎么办?
          • 好! 筒子们智慧是无穷滴......请见内:
            这么改行吗?

            try {
            某男人.小便(某男厕所.get马桶( ) );
            }catch (找不到马桶的异常 某异常) {
            某男人.国骂( );
            throw 某异常;
            }
            finally{
            某男人.拉上裤子拉链( );
            }
            • 为什么不是"某男人.小便(男厕所集合.get最近的空马桶( ) );" 会不会同时有两个男人同时找到同一个空马桶(多线程),是不是要lock? 问题是不是开始复杂化了?
              • 这会是以后章节的话题。《厕所是如何建成的》是个系列文,会针对不同主题的。不过内容都是在盖厕所,呵呵。
                • 这厕所盖得很有意思 :),支持继续盖。
            • 不妥, 请见内
            • 不妥, 请见内
              try {
              某男人.小便(某男厕所.get马桶( ) );
              某男人.拉上裤子拉链( );
              }catch (找不到马桶的异常 某异常) {
              某男人.拉上裤子拉链( ); //这样还是文明一点, 不过这个 某男人 有点白痴, 没马桶你解裤子干嘛?!
              某男人.国骂( );
              throw 某异常;
              }

              或:
              try {
              某男人.小便(某男厕所.get马桶( ) );
              }catch (找不到马桶的异常 某异常) {
              某男人.国骂( );
              throw 某异常;
              } finally{
              try{
              某男人.拉上裤子拉链( );
              }catch(拉链根本没打开的异常 某异常2){
              // 这就不上抛了, 自己处理
              }
              }
        • 小便应该在厕所里 - 这个是UNIVERSAL CONSTRAINT. 如何找到厕所对大人/小孩是不一样的, 但对大人和小孩各类是一样的. "某男厕所.get马桶( )" 多余 - 负担转嫁到CALLER
      • 其实是一个动作,这样好了:马桶。小便(小便者 某人)throws 马桶UnavailableException, GenderException
    • 基本同意。N年前听过一位高人讲解什么是 Object Oriented,他用的例子是工人阶级,呵呵。working class吗。什么是工人阶级?泛指那一类(class)勤奋,被剥削,没$$的人们。老张是工人阶级的一分子,so..老张是working class -- Worker 的一个object.
      • 这工人阶级, 无产阶级的例子易学易懂, 确实是高人.
        • MINYANGLI,看来我俩是出同门,因为我也听过类似的启发与教诲。老师有很好的哲学背景,他对 Java Class 的定义是 (大意):Class是自然界中一类有共性事物的统称。在听过working class 的例子后,这就好理解了。
          此外,虽然是多年前的事,但老师在讲解 JSP vs Servlet 时用的“野生动物园”的故事,也让人终生难忘。
      • MINYANGLI,再仔细讲讲工人阶级的故事!没怎么有启发呀~~
    • 建议先写 use case, 界定 system 和 actor。
    • Funny and very interesting. Some suggestions
      For non-IT people, it’s hard to understand.

      For example, do we have to distinguish male and female washroom? In our private washroom (in our house or apartment unit), there isn’t any difference, am I right?

      Can private washroom be used only privately? Can our guests and visitors use it?

      In real world, human being needs flexibility. 活人还让尿憋死

      For IT people it missed some things:
      abstract and interface in inheritance
      inheritance vs. sealed
      class member vs. static member
      value type vs. reference type.
    • 好文,特别适合小朋友偶。昨天看着这个OO发呆了半天。现在看了小人书版的天书,很有启发。偶当时是这样理解OO的,不知道对不对:
      ENCAPSULATE:打包,把东西整合起来(刚才看了小人书,知道还要留门)。等于是个的蛋壳,保护里面的正常工作,也同时控制访问?
      INHERITATE:这个和CLONE的意思一样吧?说白了就是为了减少工作,抄!
      POLYMORPHISM:这个和EDIT意思差不多吧?全文照抄不太好,改改里面的东西,就是自己的东西。不知道,OVERRIDE是不是就是小改,大局还是一样;OVERLOAD就是大改,与原来可谓没有太多关系,是全新的?
      ATTRIBUTE:这个就是实现功能的物质基础;METHOD:使用前述基础的方法。2者合一,保证功能的实现?
      权限:就是前面提到的蛋壳,控制使用的方式。
      是否正确,请告之,谢谢!
      • 用鸡蛋来说吧.
        ENCAPSULATE:蛋壳
        INHERITATE:鹌鹑蛋
        POLYMORPHISM:鸭蛋
        OVERRIDE: 红皮鸡蛋 
        OVERLOAD: 咸鸡蛋
        ATTRIBUTE:蛋清, 蛋黄. 
        METHOD:打蛋器.
        • INHERITATE:鹌鹑蛋, POLYMORPHISM:鸭蛋,如何解?OVERRIDE:红皮鸡蛋,OVERLOAD:咸鸡蛋,应该为“改性蛋的不同工艺”吧?
          • OVERRIDE:红皮鸡蛋,OVERLOAD:咸鸡蛋。理解了。红皮鸡蛋还是蛋,咸蛋和原来的蛋,味道差得比较大了
          • 咳, 就这么一瞎说. 其实你挺明白的, 所谓OO, 说到底就是 "抄".
            • 谢谢COOLMAO鼓励。IT原来是艺术,偶喜欢。
        • 不对.
          • TDR,偶错在哪里?概念差了,以后很吃力呀
            • 下面说了一个. 我推荐你看看上面那个工人阶级的例子, 喊一喊 mingyangli. 做为一个方法论的东西, 一定要抽象来谈, 举例仅仅是用来辅助说明抽象的概念的, 不要喧宾夺主,不然会被细节绕晕. 谈oo,举例一定要既抽象又具体,那个阶级的例子很好。
        • 打蛋器 is not a method of egg:)
          • 没找到内部的METHOD, 就找了个外部的蒙混下, 见笑, 见笑.
            • 发臭、破、生小鸡可能都能算:)
      • ENCAPSULATE:decoupling for a clean boundray INHERITATE:抄? wrong. It is 'to be'. It is reuse or it is showing identity. POLYMORPHISM:Aspect. An apple is fruit, eatable, round etc.
    • 好文,有趣儿,期待后续系列。
    • 嗯,挺好玩的。N年前第一次接触OO,当时的感觉就是它有话不好好说,本来就“开门”这件事,它非说“门.开”,为了弄个门出来,费老鼻子劲了,把跟“开”这个动作不相干的什么尺寸、颜色、生产厂家都整进来。
    • 其实这个故事给想要告诉我们:
      研究OO不要研究牛角尖的细节,否则别人会被恶心死得。
    • too many misunderstandings
    • 的确是给非专业人看的,专业人一看: 怎么这么长?还不如直接讲清楚,使用比喻是为了表达形象,但是比喻太多也是问题阿.