This article is from http://www.codeproject.com/Articles/93369/How-I-explained-OOD-to-my-wife
雖然本文題目里寫的是跟媳婦解釋面向對象設計,但是我廣大屌絲很少有媳婦是做軟件開發的。如果是沒有聽說過面向對象程序設計概念的媳婦,仍舊不能看懂本文。這本質上是對剛對面向對象程序設計有一點概念,寫過簡單的小程序的人寫的文章。
(歡迎轉載,請注明出處:http://bitzhuwei.cnblogs.com )
注:我知道之前有人翻譯過這篇文章了,但是我還是想自己翻譯一下,一來加深理解,二來我覺得之前的譯文多少有些生硬,還是有不符合中文的表達習慣。無論寫的好壞,歡迎批評指正!
How I explained OOD to my wife
By Al-Farooque Shubho, 2 Aug 2010
4.90/5 - 254 votes 4 removed μ 4.86, σa 0.96 [?] |
Prize winner in Competition "Best overall article of July 2010"
Introduction
引子
My wife Farhana wants to resume her career as a software developer (she started her career as a software developer, but couldn't proceed much because of our first child's birth), and these days, I am trying to help her learn Object Oriented Designs as I've got some experience in software design and development.
我媳婦方夏娜同學以前是軟件工程師,后來生孩子就不干了。現在她想重新開始。這幾天我就在輔導她學習OOD(Object Oriented Design,面向對象的設計),畢竟我是專業的嘛~
Since my early days in software development, I have always observed that no matter how hard a technical issue seems, it always becomes easier if explained from a real life perspective and discussed in a conversational manner. As we had some fruitful conversations on Object Oriented Designs, I thought I could share it because someone might find it an interesting way of learning OOD.
資深的我認為,就算某技術問題難以理解,只要從日常生活的角度去解釋,用對話的方式去交流,那就難不到哪兒去啦。現在我把我跟媳婦關於OOD的對話分享出來,我猜會有人感興趣的。
Following is how our OOD conversation took place:
對話如下。
Topic: Introducing OOD
話題:OOD第一印象
Shubho: Darling, let's start learning Object Oriented Designs. You know Object Oriented Principles, right?
本屌:親愛的,咱們開始學OOD嘍,你知道OOP(Object Oriented Principles,面向對象的原則)吧?
Farhana: You mean, Encapsulation, Inheritance, and Polymorphism, right? Yes, I know the principles.
媳婦:你說的是“封裝”、“繼承”和“多態”吧?我當然知道。
Shubho: OK, I hope you already know how to use classes and objects. Let us learn Object Oriented Designs today.
本屌:OK。那你肯定知道怎么寫一個類,然后創建對象什么的了。今天來學OOD就。
Farhana: Hold on a second. Isn't Object Oriented Principles enough to do Object Oriented programming? I mean, I can define classes and encapsulate properties and methods. I can also define a class hierarchy based upon their relationship. So, what's left?
媳婦:等等等等。我會用OOP還不夠做面向對象的編程嗎?你看,我能定義一個類,封裝屬性和方法;還知道根據需要去創建繼承它的類。你說我還有要學的嗎?
Shubho: Good question. Object Oriented Principles and Object Oriented Design are actually two different things. Let me give you a real life example to help you understand.
本屌:問的好。要知道,OOP和OOD完全是兩碼事。我舉個例子你就明白了。你小的時候學過字母表對吧。
When you were child you learned alphabets first, right?
Farhana: Yes.
媳婦:是啊。
Shubho: OK. You also learned words and how to assemble the alphabets to make those meaningful words. Along with that, you learned some basic grammar to assemble the words into sentences. For example, you had to maintain tenses, and you had to use prepositions, conjunctions, and others properly to create grammatically correct sentences. Say, a sentence like the following:
本屌:OK。你也學會了很多單詞是由哪些字母排列組成的,你還學會了怎么把單詞組成符合語法的句子。比如這個:
"I" (pronoun) "want" (Verb) "to" (Preposition) "learn" (Verb) "OOD" (Noun)
You see, you are assembling the words in some order, and you are also choosing the correct words to end up with a sentence that has some meaning.
你看,你按某種順序把單詞排列起來,
Farhana: OK, so, what does this mean?
媳婦:嗯哪……你想說什么?
Shubho: This is analogous to Object Oriented Principles. OOP says about the basic principles and the core ideas to do Object Oriented programming. Here, OOP can be compared to the basic English grammar, where the basic grammar teaches you how to construct a meaningful and correct sentence using words, and OOP teaches you to construct classes, encapsulate properties and methods inside them, and also develop a hierarchy between them and use them in your code.
本屌:這和OOP是多么類似呀。OOP是面向對象編程的基本原則和核心思想。OOP可以比作基礎的英語語法:語法告訴你如何用單詞寫出含義正確的句子,OOP告訴你如何創建一個類,給它設置屬性和方法,甚至創建繼承類。
Farhana: Hm..I got the point. So, where does OOD fit here?
媳婦:啊,原來如此。那OOD跟這個有什么關系?
Shubho: You'll get your answer soon. Now, suppose you need to write articles and essays on some topics. You may also wish to write books on different subjects that you have expertise on. Knowing how to construct sentences is not enough to write good essays/articles or books, right? You need to write a lot, and need to learn to explain things in a good way so that readers can easily understand what you are trying to say.
本屌:馬上。比方說你要寫一篇文章,或者寫本書叫月子。那你不光要知道怎么寫一句話一段話,你要寫多少多少頁的東西,還要有組織篇章結構的技巧,寫的淺顯易懂別人才容易理解,才想看你寫的,對吧。
Farhana: Seems interesting... carry on.
媳婦:啊有道理,繼續。
Shubho: Now, if you want to write a book on a particular subject (say, Learning Object Oriented Design), you got to know how to divide the subject into smaller topics. You also need to write chapters on those topics, and you need to write prefaces, introductions, explanations, examples, and many other paragraphs in the chapters. You need to design the overall book and learn some best practices of writing techniques so that the reader can easily understand what you are trying to explain. This is about the bigger picture.
本屌:具體來說,如果你想寫一本書(比如關於學習OOD的書),你要把問題划分為若干子問題,組織各個章節的內容及其先后順序,還要寫前言、序言、搜羅安排示例、弄個封面什么的。你看一下那些寫的好的書是怎么組織的,然后借鑒借鑒,最后才能寫出一本受讀者歡迎的好書。大體藍圖就是這樣。
In software development, OOD addresses the bigger picture. You need to design your software in a way that your classes and code are modularized, re-usable, and flexible, and there are some good guidelines to do that so that you don't have to re-invent the wheel. There are some design principles that you can apply to design your classes and objects. Makes sense?
換到軟件開發領域,OOD就是講怎么設計藍圖的。好的軟件藍圖,其類或者說代碼,要模塊化,具有可重用性,擴展性。因此軟件代碼的設計也有一些原則(design principles),用來指導你設計優秀的藍圖。而且,現在已經有若干前人設計的優秀藍圖被分享出來供大家借鑒,我們無須從零開始。
Farhana: Hmm.. got the initial idea, but need to learn more.
媳婦:大概理解你的意思啦,再說明白點。
Shubho: Don't worry, you will learn soon. Just let our discussion going.
本屌:OK。想更明白,請看下一話題。
Topic: Why OOD?
話題:OOD算個毛?
Shubho: This is a very important question. Why should we care about Object Oriented Design when we can create some classes quickly and finish development and deliver? Isn't that enough?
本屌:這個問題太重要了,重要到我們忘記了為什么它這么重要。你說咱輕輕爽爽的寫幾個類,把軟件做出來,把錢拿到手,不就行了么。OOD算個毛?
Farhana: Yes, I didn't know about OOD earlier, and still I was able to develop and deliver projects. So, what is the big deal?
媳婦:是啊,我以前也不懂OOD,可還是好好的做出過軟件來呀。OOD有什么了不起?
Shubho: OK, let me get a classic quote for you:
"Walking on water and developing software from a specification are easy if both are frozen."
本屌:OK。哥引用一下名人名言:
"Walking on water and developing software from a specification are easy if both are frozen."
“如果水結冰,需求說明書不改,水上漂和軟件開發同樣的易如反掌。”——愛德華V.貝拉爾
(譯者注:翻譯過來就沒意思了,frozen在英語里一語雙關,既有水結冰的意思,又有需求固定不變的意思)
Farhana: You mean software development specifications keep changing constantly?
媳婦:你的意思是軟件開發需求說明書無休止的改變?
Shubho: Exactly! The universal truth of software is "your software is bound to change". Why?
本屌:沒錯!改變無止境就是軟件的普遍真理。
Because, your software solves real life business problems and real life business processes evolve and change – always
因為,你開發的軟件解決了生活生產中的問題,而真實世界中,問題是在變化的,那真是永遠,永遠,永遠,永永遠遠地變。.
Your software does what it is supposed to do today and does it good enough. But, is your software smart enough to support "changes"? If not, you don't have a smartly designed software.
你開發的軟件能滿足今天的需求,滿足的很好。但是它能滿足“改變”嗎?如果不行,那就不是一個設計的好的軟件。
Farhana: OK, so, please explain "smartly designed software" sir!
媳婦:OK。那么怎么才算設計得好的軟件,親?
Shubho: "A smartly designed software can adjust changes easily; it can be extended, and it is re-usable."
本屌:設計良好的軟件能夠輕松地適應改變,可擴展,可重用。
And, applying a good "Object Oriented Design" is the key to achieve such a smart design. Now, when can you claim that you have applied good OOD in your code?
在代碼設計中應用OOD是實現良好設計的關鍵。那么,怎么才算是在代碼設計中應用了OOD呢?
Farhana: That's my question too.
媳婦:我也想知道。
Shubho: You are doing Object Oriented Design if your code is:
· Of course, object oriented.
· Re-usable.
· Can be changed with minimal effort.
· Can be extended without changing existing code.
施展OOD,就意味着如下內容:
當然,面向對象編程;
代碼可重用;
為了適應需求的改變,所需改動的代碼最少(改動代碼所需時間最短,等等都是這個意思);
無需改變現有代碼即可擴展新功能。
Farhana: And..?
媳婦:這……
Shubho: We are not alone. Many people have already given lots of thoughts and put a lot of effort on this issue, and they've tried to achieve good Object Oriented Design and identify some basic principles for doing Object Oriented Design (some basic inspirations which you can use to lay out your object oriented design). They also have identified some common design patterns that are applicable to common scenarios (based on the basic principles).
本屌:你不是一個人。已經有很多人為OOD付出心血,他們嘗試着應用OOD,並且總結出來一些OOD的通用原則。基於這些原則,他們給出了若干通用的設計模式(design pattern),每一張設計模式都能夠應用到一種類型的場景。
Farhana: Can you name some?
媳婦:能舉幾個OOD設計原則的例子不,親?
Shubho: Sure. There are many design principles out there, but at the basic level, there are five principles which are abbreviated as the SOLID principles (thanks to Uncle Bob, the great OOD mentor).
本屌:當然。設計原則有很多啦,其中最基礎的5個被縮寫為SOLID原則(感謝Uncle Bob,超彪悍的OOD導師)。
S = Single Responsibility Principle(單一職責原則)
O = Opened Closed Principle(開閉原則)
L = Liscov Substitution Principle(里氏替換原則)
I = Interface Segregation Principle(接口分離原則)
D = Dependency Inversion Principle(依賴倒置原則)
In the following discussion, we will try to understand each of these in detail.
下面咱們就討論一下這個SOLID原則吧。
Topic: Single Responsibility Principle
話題:單一職責原則
Shubho: Let me show you the poster first. We should thank the person who made the posters, these are really interesting.
本屌:來看一下這張海報。做海報的人可真有才。
(圖中文字:單一職責原則;你能干,不等於你應該干)
Single Responsibility Principle poster
單一職責原則的海報
It says, "just because you can implement all the features in a single device, you shouldn't". Why? Because it adds a lot of manageability problems for you in the long run.
海報告訴你:“就算你能在一件東西上做出所有的功能,你也不應該這么做”。Why?因為長期來看,這會引起巨頭疼的維護問題。
Let me tell you the principle in Object Oriented terms.
用面向對象術語說就是這樣的:
"There should never be more than one reason for a class to change."
“只能有一種理由讓你修改這個類”。
Or, differently said: "A class should have one and only one responsibility".
另一種說法是:“一個類應該有且只應該有一個原則”。
Farhana: Can you please explain?
媳婦:嘛意思啊?求詳情求解釋?
Shubho: Sure, this principle says that if you have a class that has more than one reason to change (or has more than one overall responsibility), you need to split the class into multiple classes based upon their responsibility.
本屌:好的。這個原則說的是,如果一個類有超過一個理由讓它修改代碼(或者有超過一個功能),你就要根據它的功能把它拆分開。
Farhana: Hmm... does that mean that I can't have multiple methods in a single class?
媳婦:額,這是不是說我一個類里面不能有多個方法了?
Shubho: Not at all. Rather, you surely can have multiple methods in a single class. The issue is, they have to meet a single purpose. Now, why is splitting important?
本屌:沒那回事。一個類里有多個方法是理所當然的。問題是,這些方法是為實現一個共同的功能才寫的。好了,現在想想為什么拆分功能這么重要?
It's important because:
那是因為:
· Each responsibility is an axis of change.
· Code becomes coupled if classes have more than one responsibility.
每個功能都會引起改變
一個類有多個功能就會引起緊耦合(改變這個功能的東西,會影響到另一個功能)
Farhana: Could you please give me an example?
媳婦:能不能給個例子,親?
Shubho: Sure, take a look at the following class hierarchy. Actually, this example is taken from Uncle Bob, so thanks to him again.
本屌:當然。看一下下面這個類繼承圖。實際上這也是從Uncle Bob哪里拿來的,再次感謝她。
Class hierarchy showing violation of SRP principle
違反SRP原則的類繼承圖
Here, the Rectangle class does the following:
這個Rectangle類做這些事:
· It calculates the value of the rectangular area.
· It renders the rectangle in the UI.
計算矩形面積
在UI上畫矩形
And, two applications are using this Rectangle class:
然后來了兩個應用程序調用這個Rectangle類:
· A computational geometry application uses this class to calculate the area
· A graphical application uses this class to draw a rectangle in the UI
一個幾何計算程序用這個類來計算面積
一個畫圖程序用這個類來在UI上畫矩形
This is violating the SRP (Single Responsibility Principle)!
這違反了SRP原則!
Farhana: How?
媳婦:怎么違反了?
Shubho: You see, the Rectangle class is actually performing two different things. It is calculating the area in one method, and it is returning a GUI representation of the rectangle in another method. This leads to some interesting problems:
本屌:你看,Rectangle類實際上做了兩件事,它要計算面積,還要在GUI上畫圖。問題就出在這里。
· We must include the GUI in the computational geometry application. While deploying the geometry application, we must include the GUI library.
· A change to the Rectangle class for the graphical application may lead to a change, build, and test for the computational geometry application, and vice-versa.
在幾何計算應用程序里不得不include一下GUI庫。
一旦圖形應用程序要求Rectangle類做修改,那么幾何計算應用程序的部署和測試工作就得再來一次;反之亦然。
Farhana: It's getting interesting. So I guess we should break up the class based on its responsibilities, right?
媳婦:哦,我猜我們應該把Rectangle類拆分一下。
Shubho: Exactly. Can you predict what we should do?
本屌:太對了。你估摸估摸到底該怎么拆分呢?
Farhana: Sure, let me try. Following is what we might need to do:
媳婦:恩,我覺得是這么做:
Separate the responsibilities into two different classes, such as:
把Rectangle的兩個功能(職責)分到兩個新的類里去:
· Rectangle: This class should define the area() method.
· RectangleUI: This class should inherit the Rectangle class and define the Draw() method.
新Rectangle:定義計算面積的area()方法。
RectangleUI類:繼承新Rectangle類,定義Draw()方法。
Shubho: Perfect. In this case, the Rectangle class will be used by the computational geometry application, and the RectangleUI class will be used by the graphical application. We could even separate the classes into two separate DLLs, and that will allow us not to touch the other in case a change is needed to be implemented in one.
本屌:哎呦,不錯呦。新Rectangle類用在幾何計算應用程序里,RectangleUI類用在繪圖程序里。我們還可以把這兩個類分到兩個DLL文件里。這么一來,改變其中一個類的代碼,對另一個類和它所在的DLL文件都毫無影響(不必重新測試、部署另一個)。
Farhana: Thanks, I think I understand SRP. One thing, SRP seems to be an idea of breaking things into molecular parts so that it becomes reusable and can be managed centrally. So, shouldn't we apply SRP in the method level as well? I mean, we might have written methods that have many lines of code for doing multiple things. These methods might be violating SRP, right?
媳婦:嘿嘿。SRP就是這么回事啊。等等,SRP我感覺是這么個思想:把要做的事拆分成若干小的步驟部分,這樣就可重用、便於管理維護。那我們是不是也應該把SRP這個核心思想應用到方法層次上?你想,有的方法可能有很多行代碼,它做了很多事才完成它的任務。這種方法就違反了SRP啊,對不對?
Shubho: You got it right. You should break down your methods so that each method does a particular work. That will allow you to re-use methods, and in case a change is required, you are able to do the change by modifying minimal amount of code.
本屌:對頭。這種大塊頭的方法就應該拆分一下,達到每個方法都只做一件事。這樣一來,方法也就可重用了。而且你要改代碼的時候,改動就會局限在較小的方法里,這對維護和測試都是很有益的。
Topic: Open-Closed Principle
話題:開閉原則
Shubho: Here goes the poster for the Open-Closed Principle:
本屌:先上圖:開閉原則!額,是不是有點重口味了這個。
(圖中文字:開閉原則;穿穿衣服,何必開膛破肚)
Figure: Open Closed Principle poster
海報:開閉原則
If I need to explain it in design oriented terms, it would be as follows:
用設計術語來說就是這樣的:
"Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification."
“軟件實體(類,模塊,函數,等等)要面向擴展,回避修改。”
At the most basic level, that means, you should be able to extend a class's behavior without modifying it. It's just like I should be able to put on a dress without doing any change to my body, ha ha.
簡單來說,你寫了一個類,要想擴展這個類的功能,你最好在不修改這個類的代碼的基礎上完成。好比我本來是我,冬天了想加件衣服,這不需要把我開膛破肚吧,哈哈。
Farhana: Interesting. You can change your look by putting any dress you want, and you don't have to change your body for that. So you are open for extension, right?
媳婦:額,你想穿什么就穿什么,不用自殘。所以你對擴展衣服是開放的,對吧?
Shubho: Yes. In OOD, open for extensions means that the behavior of the module/class can be extended and we can make the module behave in new and different ways as the requirements change, or to meet the needs of new applications.
本屌:對。OOD說的對擴展開放,指的是類的行為可以被擴展,我們可以根據用戶需求的改變而改變一個模塊的行為,或者說滿足新應用程序的要求。
Farhana: And your body is closed for modification. I like this example. So, the source code for a core class or module should not be modified when it needs an extension. Can you explain with some examples?
媳婦:還有你的身體對修改是關閉的。這個例子很形象。這意思是說擴展一項功能的時候,模塊原有的核心類的源代碼不應該改變。能不能再舉個例子親?
Shubho: Sure, take a look at the following example. This doesn't support the "Open-Closed" principle:
本屌:好。看下面這個示例。它是不支持開閉原則的。
Class hierarchy showing violation of Open Closed principle
類圖:違反了開閉原則的例子
You see, the Client and Server classes are both concrete. So, if for any reason, the server implementation is changed, the client also needs a change.
你看,Client類和Server類都是具體類。所以,如果Server類的定義改變了,勢必要相應改變Client類。
Farhana: Makes sense. If a browser is implemented as tightly coupled to a specific server (such as IIS), then if the server is replaced for some reason with another one (say, Apache) the browser also needs to be changed or replaced. That would be really horrible!
媳婦:言之有理嘛。如果瀏覽器是跟一個具體的服務器(例如IIS)緊耦合的,那要是把IIS換成Apache,瀏覽器跟服務器交互的部分就肯定得改了。這牽一發而動全身的改動太惡心了。
Shubho: Correct. So following would be the correct design:
本屌:正解。所以下面這種設計才是更好的。
Class hierarchy showing Open Closed Principle
類圖:符合開閉原則
In this example, there is an Abstract Server class added, and the client holds a reference to the abstract class, and the Concrete Server class implements the Abstract Server class. So, if for any reason the Server implementation is changed, the Client is not likely to require any change.
這個類圖里加了一個抽象服務器類,Client類里有一個對抽象服務器類的引用字段,然后用具體的服務器類繼承和實現抽象服務器類。如此一來,當客戶告訴你把IIS換成Apache,你只要再寫個Apache服務器的類就行了,客戶端就不受影響。
The Abstract Server class here is closed for modification, and the concrete class implementations here are open for extension.
你感覺感覺,是不是抽象服務器類對修改關閉(有事沒事都別改它的代碼),具體類的實現卻是對擴展開放的。
Farhana: As I understand, abstraction is the key, right?
媳婦:我感覺,關鍵的手段就是抽象,是嗎?
Shubho: Yes, basically, you abstract the things that are the core concepts of your system, and if you do the abstraction well, most likely, it would require no change when the functionality is to be extended (such as the server is an abstract concept). And, you define the abstract things in the implementations (say, IISServer implements the Server) and code against abstractions (Server) as much as possible. This would allow you to extend the abstract thing and define a new implementation (say, ApacheServer) without doing any change in the client code.
本屌:是的。你把系統的核心概念抽象成類,如果抽的好,以后隨便擴展具體什么功能都不會影響這些核心的東西。盡可能的把事情抽象化,然后在具體類(IISServer什么的)里去實現那些抽象定義。那么以后你想擴展抽象類(比如寫個ApacheServer什么的)就不會牽涉到客戶端的代碼了。
Topic: Liskov's Substitution Principle
話題:里氏替換原則
Shubho: The name "Liskov's Substitution Principle" sounds very heavy, but the idea is pretty basic. Take a look at this interesting poster:
本屌:里氏替換原則聽起來很嚇人,其實一點也不難。繼續先上圖:
(圖中文字:里氏替換原則;浮水為鴨,呱呱為鴨,充電非鴨,笨呀你丫)
Liskov Substitution Principle poster
里氏替換原則的海報
The principle says:
這個原則告訴我們:
"Subtypes must be substitutable for their base types."
“基類型出現的地方必須能夠用子類型代替。”
Or, if said differently:
換個方式說是:
"Functions that use references to base classes must be able to use objects of derived classes without knowing it."
“基類的函數在子類里面也必須正常使用。”
Farhana: Sorry, sounds confusing to me. I thought this is the basic rule of OOP. This is polymorphism, right? Why was an Object Oriented Principle required on this issue?
媳婦:我迷茫了。我以為你在講OOP,可這是多態吧?為什么OOP會講這個?
(注:譯者認為是繼承,不是多態)
Shubho: Good question. Here is your answer:
本屌:問的好,是這樣的。
In basic Object Oriented Principles, "Inheritance" is usually described as an "is a" relationship. If a "Developer" is a "SoftwareProfessional", then the "Developer" class should inherit the "SoftwareProfessional" class. Such "Is a" relationships are very important in class designs, but it's easy to get carried away and end up in a wrong design with a bad inheritance.
在基礎的OOP里面,繼承被描述成是“是一個”的關系。如果“開發者”是一個“軟件專家”,那么“開發者”類就應該繼承“軟件專家”類。類設計中的這種“是一個”的關系是非常重要的,但是你很容易被迷惑而做出錯誤的類繼承設計。
The "Liskov's Substitution Principle" is just a way of ensuring that inheritance is used correctly.
里氏替換原則就是一種保證正確使用繼承的方法。
Farhana: I see. Interesting.
媳婦:明白了,這個好像很有用。
Shubho: Yes darling, indeed. Let's take a look at an example:
本屌:當然了親,咱們再看個例子來。
Class hierarchy showing an example of Liskov Substitution Principle
符合里氏替換原則的類繼承圖
Here, the KingFisher class extends the Bird base class and hence inherits the Fly() method, which is pretty good.
此示例中KingFisher(翠鳥)類擴展了Bird類,因此它繼承了Fly()方法。這沒問題。
Now take a look at the following example:
現在我加上個東西你再看。
Corrected class hierarchy of Liskov Substitution Principle
修改之后的類繼承圖違反了里氏替換原則
Ostrich is a Bird (definitely it is!) and hence it inherits the Bird class. Now, can it fly? No! Here, the design violates the LSP.
Ostrich(鴕鳥)是一個鳥類(這肯定的),然后我們就讓Ostrich類繼承了Bird類。問題來了,鴕鳥能飛嗎?不能啊!這就違反了里氏替換原則。
So, even if in real world this seems natural, in the class design, Ostrich should not inherit the Bird class, and there should be a separate class for birds that can't really fly and Ostrich should inherit that.
所以說,就算在真實世界里你可以說鴕鳥是一個鳥類,但是在類設計里,Ostrich就不應該繼承Bird類。應該是有一個單獨的類代表不能飛的鳥,讓Ostrich繼承它。
Farhana: OK, understood. So, let me try to point out why the LSP is so important:
媳婦:原來如此。讓我試試總結一下LSP的重要性在哪兒。
· If LSP is not maintained, class hierarchies would be a mess, and if a subclass instance was passed as parameter to methods, strange behavior might occur.
· If LSP is not maintained, unit tests for the base classes would never succeed for the subclass.
· 若不滿足LSP,類繼承將是一團亂麻。若子類的實例作為參數傳遞給一個方法,會發生各種奇葩的事。
· 若不滿足LSP,對基類的單元測試對子類就通不過了。
Am I right?
我說的對不?
Shubho: You are absolutely right. You can design objects and apply LSP as a verification tool to test the hierarchy whether inheritance is properly done.
本屌:你說的太對了。類圖設計完的時候你就可以用LSP原則作為驗證工具來檢驗你寫的繼承關系是不是合適。
Topic: The Interface Segregation Principle
話題:接口分離原則
Shubho: Today, we will learn the "Interface Segregation Principle". Here is the poster:
本屌:今天我們學習“接口分離原則”。再來看個海報來:
(圖中文字:接口分離原則;這個USB口,打死我也不知道該插在哪兒啊?!)
Interface Segregation Principle poster
海報:接口分離原則
Farhana: What does it mean?
媳婦:這是什么意思?
Shubho: It means the following:
"Clients should not be forced to depend upon interfaces that they do not use."
本屌:意思是:“客戶端代碼不應該費勁去弄懂他用不到的接口”。
Farhana: Explain please.
媳婦:具體解釋一下親?
Shubho: Sure, here is your explanation:
本屌:恩。這么說吧:
Suppose you want to purchase a television and you have two to choose from. One has many switches and buttons, and most of those seem confusing and doesn't seem necessary to you. Another has a few switches and buttons, which seems familiar and logical to you. Given that both televisions offer roughly the same functionality, which one would you choose?
好比你想買一台電視機,有兩種可選的。一種是有很多開關和按鈕,大多數開關都不知道是干嘛的,也不知道有用沒用。另一種只有幾個開關和按鈕,看起來又熟悉又容易理解。如果這兩台電視功能一樣,你選哪個?
Farhana: Obviously the second one with the fewer switches and buttons.
媳婦:當然是開關少的那個。
Shubho: Yes, but why?
本屌:是的,但是為什么呢?
Farhana: Because I don't need the switches and buttons that seem confusing and unnecessary to me.
媳婦:因為我又不需要那些亂七八糟的沒用的開關。
Shubho: Correct. Similarly, suppose you have some classes and you expose the functionality of the classes using interfaces so that the outside world can know the available functionality of the classes and the client code can be done against interfaces. Now, if the interfaces are too big and have too many exposed methods, it would seem confusing to the outside world. Also, interfaces with too many methods are less re-usable, and such "fat interfaces" with additional useless methods lead to increased coupling between classes.
本屌:對。類似的,假設你寫了一些類,用接口暴露他們的功能。這樣客戶端代碼就可以通過接口調用你寫的類。可是,如果接口里的方法太多,那別人調用你的接口的時候就不容易弄明白該怎么用。而且這樣的接口也缺少可重用性。這種所謂的“富接口”也增加了類之間的耦合性。
This also leads to another problem. If a class wants to implement the interface, it has to implement all of the methods, some of which may not be needed by that class at all. So, doing this also introduces unnecessary complexity, and reduces maintainability or robustness in the system.
還沒完。如果別人需要寫一個類實現這個接口,他就得實現接口里所有的方法,其中肯定有很多方法他根本用不着。這就平白增加了代碼,降低了系統的可維護性。
The Interface Segregation principle ensures that Interfaces are developed so that each of them has their own responsibility and thus they are specific, easily understandable, and re-usable.
接口分離原則告訴你要讓接口簡單,只做它必須做的事,這樣才易懂易重用。
Farhana: I see. You mean interfaces should contain only the necessary methods and not anything else?
媳婦:明白啦。你是說接口應該只包含盡可能少的必須的方法,其他的都不能有?
Shubho: Exactly. Let's see an example.
本屌:正解。來看個例子。
The following interface is a "Fat interface" which violates the Interface Segregation principle:
下面這個接口就是“富接口”,違反了接口分離原則。
Example of an interface violating the Interface Segregation principle
違反接口分離原則的示例
Note that the IBird interface has many bird behaviours defined along with the Fly() behaviour. Now, if a Bird class (say, Ostrich) implements this interface, it has to implement the Fly() behaviour unnecessarily (Ostrich doesn't fly).
你看IBird接口實現了若干鳥類的行為,包括Fly()這個行為。那如果要給鴕鳥類實現這個接口,就說不通了。因為鴕鳥不會飛啊。
Farhana: That's correct. So, this interface must be split?
媳婦:恩是。那應該把這個接口拆分一下?
Shubho: Yes. The "Fat Interface" should be broken down into two different interfaces, IBird and IFlyingBird, where the IFlyingBird inherits IBird.
本屌:對。這個“富接口”應該拆成兩個接口IBird和IFlyBird,讓IFlyBird繼承IBird。
Correct version of the interface in the Interface Segregation principle example
接口分離原則示例的正解
If there is a bird that can't fly (say, Ostrich), it would implement the IBird interface. And if there is a bird that can fly (say, KingFisher), it would implement the IFlyingBird interface.
如果有不會飛的鳥類,讓它實現IBird接口,如果是會飛的鳥類,讓它實現IFlyBird接口。
Farhana: So, if I go back to the example with the television with many switches and buttons, the manufacturer of that television must have a blueprint of that television where the switches and buttons are included in the plan. Whenever they want to create a new model of the television, if they need to re-use this blueprint, they would need to create as many switches and buttons as included in the plan. That wouldn't allow them to re-use the plan, right?
媳婦:那我覺得那個N多按鈕的電視的例子,廠家有一張設計藍圖,要是廠家想造一種新款式的電視,還想重用之前的藍圖的話,就必須還設計那么多按鈕。所以這個藍圖就不能重用了。
Shubho: Right.
本屌:對對。
Farhana: And, if they really want to re-use their plans, they should divide their television's blueprint into smaller pieces so that they can re-use the plan whenever any new kind of television is to be created.
媳婦:廠家要是想重用藍圖,就應該把它分解為小的部分。這樣生產新款式的時候原來的藍圖就可以拿來用了。
Shubho: You got the idea.
本屌:你已窺門徑。
Topic: The Dependency Inversion Principle
話題:依賴倒置原則
Shubho: This is the last principle among the SOLID principles. Here is the poster:
本屌:這是SOLID原則的最后一個了。看下圖先。
(圖中文字:依賴倒置原則;你會把燈泡直接焊到火線上嗎?)
Dependency Inversion principle poster
依賴倒置原則的海報
It says..
"High level modules should not depend upon low level modules. Rather, both should depend upon abstractions."
意思是:“高層模塊不應該依賴於低層模塊。兩者都應該依賴於抽象。”
Shubho: Let's consider a real world example to understand it. Your car is composed of lots of objects like the engine, the wheels, the air conditioner, and other things, right?
本屌:我們用現實生活中的例子來說明。你的汽車是由很多東西組成的,包括引擎,輪子,空調,其他的等等。是吧?
Farhana: Yes, of course.
媳婦:當然了。
Shubho: OK, none of these things are rigidly built within a single unit; rather, each of these is "pluggable" so that when the engine or the wheel has problem, you can repair it (without repairing the other things) and you can even replace it.
本屌:這些都沒有做成連在一起分不開的整體。每一個都是“可插拔”的。如果引擎或者輪子壞了,你可以只修理引擎、輪子或者換掉就行了。
While replacement, you just have to ensure that the engine/wheel conforms to the car's design (say, the car would accept any 1500 CC engine and will run on any 18 inch wheel)
換的時候,你只要確保引擎/輪子符合車子的設計(比如,車子使用1500CC的引擎和18英寸的輪子)。.
Also, the car might allow you to put a 2000 CC engine in place of the 1500 CC, given the fact that the manufacturer (say, Toyota) is the same.
車子可能還允許你裝一個2000CC的引擎,如果是統一廠家的產品的話(豐田什么的)。
Now, what if the different parts of your car were not built in such a "pluggable nature"?
現在你想象一下,如果車子各個部分不是“可插拔”的,會怎么樣?
Farhana: That would be horrible! Because, in that case, if your car's engine is out of order, you will have to fix the whole car or purchase a new one!
媳婦:那太恐怖了!因為如果引擎壞掉了,我得把整個車子修理一遍或者買個新的。
Shubho: Yes. Now, how can the "pluggable nature" be achieved?
本屌:對,那么怎么實現“可插拔”呢?
Farhana: "Abstraction" is the key, right?
媳婦:關鍵在於“抽象”吧?
Shubho: Yes. In real world, Car is the higher level module/entity, and it depends on the lower level modules/entities like the Engines or Wheels.
本屌:對。真實世界里,汽車是高層模塊,它依賴低層模塊,比如引擎和輪子。
Rather than directly depending on the Engines or Wheels, the car depends on the abstraction of some specification of Engine or Wheels so that if any the Engine or Wheel conforms to the abstraction, these could be assembled with the car and the car would run.
車子不是直接依賴引擎和輪子的,而是他們的抽象說明。然后任何滿足這個抽象的引擎和輪子都能夠組裝到車子上了。
Let's take a look at the following class diagram:
看一下下面的類圖。
Dependency Inversion principle class hierarchy
依賴倒置原則的類圖
Shubho: In the above Car class, notice that there are two properties, and both of these are of abstract type (Interface) rather than concrete type.
本屌:在上面的Car類里,有兩個屬性,都是抽象類型(接口)的。
The Engine and Wheels are pluggable because the car would accept any object implementing the declared interfaces, and that will not require any change in the Car class.
車子能改引用任何實現了對應接口的引擎和輪子,這就是“可插拔”的,而且換不同類型的引擎和輪子不需要修改Car類型的代碼。
Farhana: So, if Dependency Inversion is not implemented in the code, we run the risk of:
媳婦:那么如果不按照依賴倒置原則,就可能發生下面的情況:
· Damaging the higher level code that uses the lower level classes.
· Requiring too much time and effort to change the higher level code when a change occurs in the lower level classes.
· Producing less-reusable code.
· 調用底層類的高層代碼被推倒重來
· 底層代碼修改時,不得不大量修改高層代碼
Shubho: You got it perfect darling!
本屌:你說的太好了親!
(譯者注:本人認為依賴倒置原則這個名字不太好,應該叫做依賴抽象原則)
Summary
再回首
Shubho: There are many other Object Oriented principles other than the SOLID principles. Some are:
本屌:除了SOLID原則外,還有很多別的OOP原則。比如:
· "Composition over Inheritance": This says about favoring composition over inheritance.
· "Principle of least knowledge": This says that "the less your class knows, the better".
· "The Common Closure principle" : This says that "related classes should be packaged together".
· "The Stable Abstractions principle": This says that "the more stable a class is, the more it must consist of abstract classes."
· 組合優於繼承:說的是盡量組合,這比繼承好。
· 傻瓜原則:說的是你的類知道的東西越少越好。
· 閉包原則:說的是把相關的類打包到一起。
· 穩定抽象原則:說的是想少改動一個類的話,就盡量用抽象的東西定義它。
Farhana: Shouldn't I learn those principles too?
媳婦:我是不是也得學這些啊?
Shubho: Yes, of course. You have the whole World Wide Web to learn from. Just Google on those principles and try to understand. And of course, don't hesitate me to ask me if you need help.
本屌:恩學學總是好的。隨便上Google百度一下就是了。當然,需要哥就說話,隨叫隨到。
Farhana: I've heard there are many Design Patterns built upon those design principles.
媳婦:我聽說基於這些設計原則,人們搞出了好多傳說中的“設計模式”?
Shubho: You are right. Design Patterns are nothing but some commonly suggested design suggestions in commonly recurring situations. These are mainly inspired by the Object Oriented Design principles. You can think of Design Patterns as "Frameworks" and OOD principles as "Specifications".
本屌:對的。設計模式就是在某些情景下大家推薦使用的設計方法。它們很好的符合OOD的原則。如果說OOD是原則,那么設計模式就是遵照這些原則而出現的宏觀設計圖。
Farhana: So, am I going to learn Design Patterns next?
媳婦:那我下一步該學設計模式啦?
Shubho: Yes darling.
本屌:沒錯親。
Farhana: That would be exiting, right?
媳婦:好激動~
Shubho: Yes, that would be really exiting.
本屌:必須滴!
Next
后文
· How I explained Design Patterns to my wife: Part I
· (譯者:未完待續——給媳婦解釋設計模式)
License
版權
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
本文及其源代碼等文檔基於CPOL。
(歡迎轉載,請注明出處:http://bitzhuwei.cnblogs.com )