ç»ã€ŠWhen I click “object-oriented”…》
派生类é‡å†™çˆ¶ç±»æ–¹æ³•å¯èƒ½è¿åLiskov替æ¢åŽŸåˆ™ï¼Ÿ
å¦‚æžœçˆ¶ç±»ä»…ä»…å£°æ˜Žäº†æŠ½è±¡æ–¹æ³•ï¼Œè€Œå„æ´¾ç”Ÿç±»åˆ†åˆ«å®žçŽ°äº†è¯¥æ–¹æ³•ï¼Œé‚£ä¹ˆå°±å¦‚åŒå®žçŽ°æŽ¥å£ä¸€æ ·ï¼Œå¯è¾¾åˆ°å¤šæ€çš„目的;
å¦‚æžœçˆ¶ç±»å®žçŽ°äº†æŸæ–¹æ³•,那么它对外所æè¿°çš„行为也就确定了,派生类如果é‡å†™è¿™ä¸ªæ–¹æ³•,那么就修改了这个行为,当派生类实例被父类型的引用使用时,表现出的行为与父类本身的实例ä¸ç›¸ç¬¦ï¼Œå³è¿å了Liskov substitution principle。
举个例å
现实ä¸ï¼Œæ£æ–¹å½¢æ˜¯çŸ©å½¢çš„一ç§ç‰¹æ®Šå½¢å¼ã€‚
现在先有Rectangle作为父类,具有heightå’Œwidth两个property(有邪æ¶çš„getter/setterï¼‰ï¼›å†æœ‰Square继承Rectangleåšå类,由于Square长与高相ç‰ï¼Œæ‰€ä»¥é‡å†™heightå’Œwidthçš„setæ–¹æ³•ä¸ºåŒæ—¶è®¾ç½®é•¿ä¸Žé«˜ã€‚至æ¤ä¼¼ä¹Žæ˜¯è®¾è®¡ä¸ŽçŽ°å®žå®Œå…¨ç›¸ç¬¦ï¼ŒæŽ¥ç€æœ‰äººè¿™æ ·è°ƒç”¨äº†ï¼š
void tryAreaCalculation(Rectangle rectangle) { rectangle.setHeight(4); rectangle.setWidth(5); assertEquals(20, rectangle.area()); } .... tryAreaCalculation(new Square());
结果assertion失败,“expect: 20, but was 25.†也许我们会说,明知é“ä¼ å…¥çš„æ˜¯Squareå¯¹è±¡è¿˜å†™é‚£æ ·çš„assertion是ä¸å¯èƒ½å‡ºçŽ°çš„ï¼Œä½†ä¸æ¸…楚程åºçš„人如果åªçœ‹tryAreaCalculation方法,就会认为“矩形é¢ç§¯=长×高=4×5=20â€œæ˜¯ç†æ‰€å½“ç„¶çš„ã€‚è¿™æ˜¾ç„¶ä¸æ˜¯æˆ‘们想看到的事。
当然,这个例å并䏿˜¯Liskov替æ¢åŽŸåˆ™æ‰€é’ˆå¯¹é—®é¢˜çš„å…¸åž‹ä¾‹åï¼Œåœ¨ä»¥â€œä¸æ‹©æ‰‹æ®µåœ°å¤ç”¨ä»£ç â€ä¸ºç›®çš„的继承例åä¸ï¼ˆclass Students extends List<Student>),大家更能明白Liskov替æ¢åŽŸåˆ™çš„æ„义,以åŠå¯¹ç»„åˆå’Œç»§æ‰¿çš„选择应首先去考虑é¢å‘对象的模型。
ä¸è¦è®©OO的眼光被具体编程è¯è¨€é®æŒ¡
æ˜¯ä¸æ˜¯è§‰å¾—我把类继承妖é”åŒ–äº†å‘¢ï¼Ÿæœ‰æ²¡æœ‰å› ä¸ºæ‹…å¿ƒäººç±»è¢«å®˜å‘˜ç±»ç»§æ‰¿å°±ä¸æ•¢ç»™äººç±»æ·»åŠ â€œè¯´è¯â€çš„æ–¹æ³•呢?ä¸å¿…è¿™æ ·ã€‚æˆ‘ä»¬åœ¨ç”¨é¢å‘å¯¹è±¡ç¼–ç¨‹æ—¶è¦æ¸…楚,什么是从é¢å‘对象建模角度认为对的事,什么是所使用的编程è¯è¨€èƒ½å¤Ÿåšåˆ°çš„事。
å¦‚æžœä½ æ‰‹ä¸Šçš„æ˜¯Javaè¯è¨€ï¼Œå‘现官员会说è¯ï¼Œäººä¹Ÿä¼šè¯´è¯ï¼Œå®˜å‘˜åˆæ˜¯äººçš„一ç§ï¼Œé‚£ä¹ˆå°±åœ¨äººç±»ä¸å®žçŽ°â€œè¯´è¯â€è¿™ä¸ªæ–¹æ³•,å†è®©å®˜å‘˜ç±»ç»§æ‰¿äººç±»ï¼ˆå³ä¾¿åœ¨æœªæ¥å¯èƒ½ä¼šåœ¨å®˜å‘˜ç±»ä¸é‡å†™è¯´è¯æ–¹æ³•ï¼ŒåŠ å…¥è¯´ç©ºè¯çš„è¯å¥ï¼‰ï¼Œè¿™ä¸€åˆ‡å·²æ˜¯ä½ 能åšåˆ°çš„åˆç†çš„äº‹äº†ã€‚ä½†è¯·å¿ƒé‡Œæ¸…æ¥šï¼Œè¿™å¹¶ä¸æ˜¯ä½¿ç”¨OOPå¯¹å¾…æ¤æ¨¡åž‹çš„æœ€æ£ç¡®æ–¹æ¡ˆï¼Œå› 为Javaè¯è¨€çš„é™åˆ¶ã€‚
如果编程è¯è¨€æœ‰äº†å¦‚Mixin的特性(例如Rubyä¸çš„Mixinã€Scalaä¸çš„trait,下é¢ä»¥Rubyä¸ºä¾‹ï¼‰ï¼Œé‚£ä¹ˆä½ ä¼šå‘çŽ°åœ¨è¿™ä¸ªé—®é¢˜ä¸Šä½ èƒ½æœ‰æ›´å¥½çš„è§£å†³æ–¹æ¡ˆã€‚ä¸ºäº†å®˜å‘˜ã€æ•™æŽˆç‰ä¹Ÿæ˜¯äººçš„äº‹å®žï¼Œæˆ‘ä»¬ä¾æ—§è®©è¿™äº›ç±»ç»§æ‰¿äººç±»ï¼Œä½†é™¤äº†å›ºæœ‰å±žæ€§å¦‚èº«é«˜ã€æ€§åˆ«ï¼Œä»¥åŠå›ºæœ‰è¡Œä¸ºå¦‚ç¡è§‰ï¼Œä¸ç»§æ‰¿ä»»ä½•å¯å˜çš„å› ç´ ï¼›æŠŠå¯èƒ½å…±ç”¨çš„å› ç´ éƒ½å•妿”¾åœ¨Moduleä¸ï¼Œä¹‹åŽåœ¨éœ€è¦çš„ç±»ä¸Mixinè¿›æ¥ï¼Œå¦‚为程åºå‘˜ã€å¸æœºã€ä¸å¦ç”Ÿç‰ç±»Mixin普通“说è¯â€æ–¹æ³•所在的Module,而在官员类ä¸å®šä¹‰å«è¯´ç©ºè¯é€»è¾‘的“说è¯â€æ–¹æ³•。
总结下ç»éªŒ
- 设计时的考虑,应首先尊é‡ä½¿ç”¨é¢å‘å¯¹è±¡æ€æƒ³çš„建模,其次å‚照具体编程è¯è¨€çš„特性,第三考虑与已有设计的é…åˆå’Œçº¦å®šï¼Œå¿…è¦æ—¶åšæŒæ£ç¡®çš„事去争å–。
- ç”¨æŽ¥å£æè¿°è¡Œä¸ºï¼Œå„ç±»é€šè¿‡å®žçŽ°æŽ¥å£æ¥å®šä¹‰è¡Œä¸ºçš„å…·ä½“å†…å®¹ï¼›ç•™æ„æŽ¥å£éš”离(ISP)。
- 用基类抽象固有属性和行为,å‡å°‘public方法,åˆç†ä½¿ç”¨Template method模å¼ï¼›å类(尽é‡ï¼‰ä¸åŽ»é‡å†™ç»§æ‰¿è‡ªåŸºç±»çš„è¡Œä¸ºï¼Œåªæ·»åŠ æ–°å±žæ€§å’Œè¡Œä¸ºï¼ˆLSP, OCP)。
- ç”¨ç»„åˆæè¿°ä»¥å€Ÿç”¨å…¶ä»–å¯¹è±¡çš„è¡Œä¸ºä¸ºç›®çš„çš„è®¾è®¡ã€‚