如何向妻子解釋OOD(轉)

前言

  此文譯自CodeProject上<How I explained OOD to my wife>一文,該文章在Top Articles上排名第3,讀了之后覺得非常好,就翻譯出來,供不想讀英文的同學參考學習。

  作者(Shubho)的妻子(Farhana)打算重新做一名軟件工程師(她本來是,后來因為他們孩子出生放棄了),于是作者就試圖根據自己在軟件開發設計方面的經驗幫助她學習面向對象設計(OOD)。

  自作者從事軟件開發開始,作者常常注意到不管技術問題看起來多復雜,如果從現實生活的角度解釋并以對答的方式討論,那么它將變得更簡單。現在他們把在OOD方面有些富有成效的對話分享出來,你可能會發現那是一種學習OOD很有意思的方式。

  下面就是他們的對話:

OOD簡介

Shubho:親愛的,讓我們開始學習OOD吧。你了解面向對象原則嗎?

Farhana:你是說封裝,繼承,多態對嗎?我知道的。

Shubho:好,我希望你已了解如何使用類和對象。今天我們學習OOD。

Farhana:等一下。面向對象原則對面向對象編程(OOP)來說不夠嗎?我的意思是我會定義類,并封裝屬性和方法。我也能根據類的關系定義它們之間的層次。如果是,那么還有什么?

Shubho:問得好。面向對象原則和OOD實際上是兩個不同的方面。讓我給你舉個實際生活中的例子幫你弄明白。

    ?再你小時候你首先學會字母表,對嗎?

Farhana:嗯

Shubho:好。你也學了單詞,并學會如何根據字母表造詞。后來你學會了一些造句的語法。例如時態,介詞,連詞和其他一些讓你能造出語法正確的句子。例如:

  "I" (代詞) "want" (動詞) "to" (介詞) "learn" (動詞) "OOD"(名詞)。

看,你按照某些規則組合了單詞,并且你選擇了有某些意義的正確的單詞結束了句子。

Farhana:OK,這意味著什么呢?

Shubho:面向對象原則與這類似。OOP指的是面向對象編程的基本原則和核心思路。在這里,OOP可以比作英語基礎語法,這些語法教你如何用單詞構造有意義且正確的句子,OOP教你在代 碼中構造類,并在類里封裝屬性和方法,同時構造他們之間的層次關系。

Farhana:嗯..我有點感覺了,這里有OOD嗎?

Shubho:馬上就有答案。現在假定你需要就某些主題寫幾篇文章或隨筆。你也希望就幾個你擅長主體寫幾本書。對寫好文章/隨筆或書來說,知道如何造句是不夠的,對嗎?為了使讀者能更輕 ? 松的明白你講的內容,你需要寫更多的內容,學習以更好的方式解釋它。

Farhana:看起來有點意思...繼續。

Shubho: 現在,如果你想就某個主題寫一本書,如學習OOD,你知道如何把一個主題分為幾個子主題。你需要為這些題目寫幾章內容,也需要在這些章節中寫前言,簡介, 例子和其他段落。 ? 你需要為寫個整體框架,并學習一些很好的寫作技巧以便讀者能更容易明白你要說的內容。這就是整體規劃。

  在軟件開發中,OOD是整體思路。在某種程度上,設計軟件時,你的類和代碼需能達到模塊化,可復用,且靈活,這些很不錯的指導原則不用你重新發明創造。確實有些原則你已經在你的類和對象中已經用到了,對嗎?

Farhana:嗯...有個大概的印象了,但需要繼續深入。

Shubho:別擔心,你馬上就會學到。我們繼續討論下去。

為什么要OOD?

Shubho:這是一個非常重要的問題。當我們能很快地設計一些類,完成開發并發布時,為什么我們需要關心OOD?那樣子還不夠嗎?

Farhana:嗯,我早先并不知道OOD,我一直就是開發并發布項目。那么關鍵是什么?

Shubho:好的,我先給你一句名言:

  走在結冰的河邊不會濕鞋,開發需求不變的項目暢通無阻(Walking on water and developing software from a specification are easy if both are frozen)

  -Edward V.?Berard

Farhana:你的意思是軟件開發說明書會不斷變化?

Shubho:非常正確!軟件開發唯一的真理是“軟件一定會變化”。為什么?

  因為你的軟件解決的是現實生活中的業務問題,而現實生活中得業務流程總是在不停的變化。

  假設你的軟件在今天工作的很好。但它能靈活的支持“變化”嗎?如果不能,那么你就沒有一個設計敏捷的軟件。

Farhana:好,那么請解釋一下“設計敏捷的軟件”。

Shubho:"一個設計敏捷的軟件能輕松應對變化,能被擴展,并且能被復用。"

并且應用好"面向對象設計"是做到敏捷設計的關鍵。那么,你什么時候能說你在代碼中很好的應用了OOD?

Farhana:這正是我的問題。

Shubho:如果你代碼能做到以下幾點,那么你就正在OOD:

  • 面向對象
  • 復用
  • 能以最小的代價滿足變化
  • 不用改變現有代碼滿足擴展

Farhana:還有?

Shubho:我們并不是孤立的。很多人在這個問題上思考了很多,也花費了很大努力,他們試圖做好OOD,并為OOD指出幾條基本的原則(那些靈感你能用之于你的OOD)。他們最終也確實總結出了一些通用的設計模式(基于基本的原則)。

Farhana:你能說幾個嗎?

Shubho:當然。這里有很多涉及原則,但最基本的是叫做SOLID的5原則(感謝Uncle Bob,偉大OOD導師)。

?

S = 單一職責原則 Single Responsibility Principle
O = 開放閉合原則 Opened Closed Principle 
L = Liscov替換原則 Liscov Substitution Principle
I = 接口隔離原則 Interface Segregation Principle
D = 依賴倒置原則 Dependency Inversion Principle

?

接下去,我們會仔細探討每一個原則。

單一職責原則

Shubho:我先給你展示一張海報。我們應當謝謝做這張海報的人,它非常有意思。

單一職責原則海報

它說:"并不是因為你能,你就應該做"。為什么?因為長遠來看它會帶來很多管理問題。

從面向對象角度解釋為:"引起類變化的因素永遠不要多于一個。"

或者說"一個類有且只有一個職責"。

Farhana:能解釋一下嗎?

Shubho:當然,這個原則是說,如果你的類有多于一個原因會導致它變化(或者多于一個職責),你需要一句它們的職責把這個類拆分為多個類。

Farhana:嗯...這是不是意味著在一個類里不能有多個方法?

Shubho:不。你當然可以在一個類中包含多個方法。問題是,他們都是為了一個目的。如今為什么拆分是重要的?

那是因為:

  • 每個職責是軸向變化的;
  • 如果類包含多個職責,代碼會變得耦合;

Farhana:能給我一個例子嗎?

Shubho:當然,看一下下面的類層次。當然這個例子是從Uncle Bob那里得來,再謝謝他。

違反單一職責原則的類結構圖

這里,Rectangle類做了下面兩件事:

  • 計算矩形面積;
  • 在界面上繪制矩形;

并且,有兩個應用使用了Rectangle類:

  • 計算幾何應用程序用這個類計算面積;
  • 圖形程序用這個類在界面上繪制矩形;

這違反了SRP(單一職責原則);

Farhana:如何違反的?

Shubho:你看,Rectangle類做了兩件事。在一個方法里它計算了面積,在另外一個方法了它返回一個表示矩形的GUI。這會帶來一些有趣的問題:

在計算幾何應用程序中我們必須包含GUI。也就是在開發幾何應用時,我們必須引用GUI庫;

圖形應用中Rectangle類的變化可能導致計算幾何應用變化,編譯和測試,反之亦然;

Farhana:有點意思。那么我猜我們應該依據職責拆分這個類,對嗎?

Shubho:非常對,你猜我們應該做些什么?

Farhana:當然,我試試。下面是我們可能要做的:

拆分職責到兩個不同的類中,如:

  • Rectangle:這個類應該定義Area()方法;
  • RectangleUI:這個類應繼承Rectangle類,并定義Draw()方法。

Shubho:非常好。在這里,Rectangle類被計算幾何應用使用,而RectangleUI被圖形應用使用。我們甚至可以分離這些類到兩個獨立的DLL中,那會允許我們在變化時不需要關心另一個就可以實現它。

Farhana:謝謝,我想我明白SRP了。SRP看起來是把事物分離成分子部分,以便于能被復用和集中管理。我們也不能把SRP用到方法級別嗎?我的意思是,我們可以寫一些方法,它們包含做很多事的代碼。這些方法可能違反SRP,對嗎?

Shubho:你理解了。你應當分解你的方法,讓每個方法只做某一項工作。那樣允許你復用方法,并且一旦出現變化,你能購以修改最少的代碼滿足變化。

開放閉合原則

Shubho:這里是開放閉合原則的海報

開放閉合原則海報

從面向對象設計角度看,它可以這么說:"軟件實體(類,模塊,函數等等)應當對擴展開放,對修改閉合。"

通俗來講,它意味著你應當能在不修改類的前提下擴展一個類的行為。就好像我不需要改變我的身體而可以穿上衣服。

Farhana:有趣。你能夠按照你意愿穿上不同的衣服來改變面貌,而從不用改造身體。你對擴展開放了,對不?

Shubho:是的。在OOD里,對擴展開發意味著類或模塊的行為能夠改變,在需求變化時我們能以新的,不同的方式讓模塊改變,或者在新的應用中滿足需求。

Farhana:并且你的身體對修改是閉合的。我喜歡這個例子。當需要變化時,核心類或模塊的源代碼不應當改動。你能用些例子解釋一下嗎?

Shubho:當然,看下面這個例子。它不支持"開放閉合"原則。

違反開發閉合原則的類結構

你看,客戶端和服務段都耦合在一起。那么,只要出現任何變化,服務端變化了,客戶端一樣需要改變。

Farhana:理解。如果一個瀏覽器以緊耦合的方式按照指定的服務器(比如IIS)實現,那么如果服務器因為某些原因被其他服務器(如Apache)替換了,那么瀏覽器也需要修改或替換。這確實很可怕!

Shubho:對的。下面是正確的設計。

遵循開放閉合原則的類結構

在這個例子中,添加了一個抽象的服務器類,客戶端包含一個抽象類的引用,具體的服務類實現了抽象服務類。那么,因任何原因引起服務實現發生變化時,客戶端都不需要任何改變。

這里抽象服務類對修改是閉合的,實體類的實現對擴展是開放的。

Farhana:我明白了,抽象是關鍵,對嗎?

Shubho:是的,基本上,你抽象的東西是你系統的核心內容,如果你抽象的好,很可能在擴展功能時它不需要任 何修改(就像服務是一個抽象概念)。如果在實現里定義了抽象的東西(比如IIS服務器實現的服務),代碼要盡可能以抽象(服務)為依據。這會允許你擴展抽 象事物,定義一個新的實現(如Apache服務器)而不需要修改任何客戶端代碼。

Liskov's 替換原則

Shubho:"Liskov's替換原則(LSP)"聽起來很難,卻是很有用的基本概念。看下這幅有趣的海報:

Liskov替換原則海報

這個原則意思是:"子類型必須能夠替換它們基類型。"

或者換個說法:"使用基類引用的函數必須能使用繼承類的對象而不必知道它。"

Farhana:不好意思,聽起來有點困惑。我認為這個OOP的基本原則之一。也就是多態,對嗎?為什么一個面向對象原則需要這么說呢?

Shubho:問的好。這就是你的答案:

在基本的面向對象原則里,"繼承"通常是"is a"的關系。如果"Developer" 是一個"SoftwareProfessional",那么"Developer"類應當繼承"SoftwareProfessional"類。在類設計中"Is a"關系非常重要,但它容易沖昏頭腦,結果使用錯誤的繼承造成錯誤設計。

"Liskov替換原則"正是保證繼承能夠被正確使用的方法。

Farhana:我明白了。有意思。

Shubho:是的,親愛的,確實。我們看個例子:

Liskov替換原則類結構圖

這里,KingFisher類擴展了Bird基類,并繼承了Fly()方法,這看起來沒問題。

現在看下面的例子:

違反Liskov替換原則類結構圖

Ostrich(鴕鳥)是一種鳥(顯然是),并從Bird類繼承。它能飛嗎?不能,這個設計就違反了LSP。

所以,即使在現實中看起來沒問題,在類設計中,Ostrich不應該從Bird類繼承,這里應該從Bird中分離一個不會飛的類,Ostrich應該繼承與它。

Farhana:好,明白了。那么讓我來試著指出為什么LSP這么重要:

  • 如果沒有LSP,類繼承就會混亂;如果子類作為一個參數傳遞給方法,將會出現未知行為;
  • 如果沒有LSP,適用與基類的單元測試將不能成功用于測試子類;

對嗎?

Shubho:非常正確。你能設計對象,使用LSP做為一個檢查工作來測試繼承是否正確。

接口分離原則

Shubho:今天我們學習"接口分離原則",這是海報:

接口分離原則海報

Farhana:這是什么意思?

Shubho:它的意思是:"客戶端不應該被迫依賴于它們不用的接口。"

Farhana:請解釋一下。

Shubho:當然,這是解釋:

假設你想買個電視機,你有兩個選擇。一個有很多開關和按鈕,它們看起來很混亂,且好像對你來說沒必要。另一個只有幾個開關和按鈕,它們很友好,且適合你使用。假定兩個電視機提供同樣的功能,你會選哪一個?

Farhana:當然是只有幾個開關和按鈕的第二個。

Shubho:對,但為什么?

Farhana:因為我不需要那些看起來混亂又對我沒用的開關和按鈕。

?

Shubho:以便外部能夠知道這些類有哪些可用的功能,客戶端代碼也能根據接口來設計.現在,如果接口太大,包含很多暴露的方法,在外界看來會很混亂.接口包含太多的方法也使其可用性降低,像這種包含了無用方法的"胖接口"會增加類之間的耦合.你通過接口暴露類的功能,對.同樣地,假設你有一些類,

這也引起了其他問題.如果一個類想實現該接口,那么它需要實現所有的方法,盡管有些對它來說可能完全沒用.所以說這么做會在系統中引入不必要的復雜度,降低可維護性或魯棒性.

接口隔離原則確保實現的接口有他們共同的職責,它們是明確的,易理解的,可復用的.

Farhana:你的意思是接口應該僅包含必要的方法,而不該包含其它的.我明白了.

Shubho:非常正確.一起看個例子.

下面是違反接口隔離原則的一個胖接口
?

?

注意到IBird接口包含很多鳥類的行為,包括Fly()行為.現在如果一個Bird類(如Ostrich)實現了這個接口,那么它需要實現不必要的Fly()行為(Ostrich不會飛).

Farhana:確實如此。那么這個接口必須拆分了?

Shubho:是的。這個"胖接口"應該拆分未兩個不同的接口,IBirdIFlyingBird,IFlyingBird繼承自IBird.

?

?

這里如果一種鳥不會飛(如Ostrich),那它實現IBird接口。如果一種鳥會飛(如KingFisher),那么它實現IFlyingBird.

Farhana:所以回頭看包含了很多開關和按鈕的電視機的例子,電視機制造商應該有一個電視機的圖紙,開關和按鈕都在這個方案里。不論任何時候,當他們向制造一種新款電視機時,如果他們想復用這個圖紙,他們將需要在這個方案里添加更多的開關和按鈕。那么他們將沒法復用這個方案,對嗎?

Shubho:對的。

Farhana:如果他們確實需要復用方案,它們應當把電視機的圖紙份為更小部分,以便在任何需要造新款電視機的時候復用這點小部分。

Shubho:你理解了。

依賴倒置原則

Shubho:這是SOLID原則里最后一個原則。這是海報

?

?

它的意思是:高層模塊不應該依賴底層模塊,兩者都應該依賴其抽象

Shubho:考慮一個現實中的例子。你的汽車是由很多如引擎,車輪,空調和其它等部件組成,對嗎?

Farhana:是的

Shubho:好,它們沒有一個是嚴格的構建在一個單一單元里;換句話說,它們都是可插拔的,因此當引擎或車輪出問題時,你可以修理它(而不需要修理其它部件),甚至可以換一個。

在替換時,你僅需要確保引擎或車輪符合汽車的設計(如汽車能使用任何1500CC的引擎或任何18寸的車輪)。

當然,汽車也可能允許你在1500CC引擎的地方安裝一個2000CC的引擎,事實上對某些制造商(如豐田汽車)是一樣的。

現在,如果你的汽車的零部件不具備可插拔性會有什么不同?

Farhana:那會很可怕!因為如果汽車的引擎出故障了,你可能修理整部車或者需要買一個新的。

Shubho:是的,那么該如何做到"可插拔性"呢?

Farhana:這里抽象是關鍵,對嗎?

Shubho:是的,在現實中,汽車是高級模塊或實體,它依賴于低級模塊或實體,如引擎或車輪。

相比直接依賴于引擎或車輪,汽車應依賴于某些抽象的有規格的引擎或車輪,以便于如果任何引擎或車輪符合抽象,那么它們都能組合到汽車中,汽車也能跑動。

一起看下面的類圖

?

?

Shubho:注意到上面Car類有兩個屬性,它們都是抽象類型(接口)。引擎和車輪是可插拔的,因為汽車能接受任何實現了聲明接口的對象,并且Car類不需要做任何改動。

Farhana:所以,如果代碼中不用依賴倒置,我們將面臨如下風險:

  • 使用低級類會破環高級代碼;

  • 當低級類變化時需要很多時間和代價來修改高級代碼;

  • 產生低復用的代碼;

Shubho:你完全掌握了,親愛的!

?總結

Shubho:除SOLID原則外還有很多其它的面向對象原則。如:

"組合替代繼承":這是說相對于繼承,要更傾向于使用組合;

"笛米特法則":這是說"你的類對其它類知道的越少越好";

"共同封閉原則":這是說"相關類應該打包在一起";

"穩定抽象原則":這是說"類越穩定,越應該由抽象類組成";

Farhana:我應該學習那些原則嗎?

Shubho:當然可以。你可以從整個網上學習。僅僅需要Google一下那些原則,然后嘗試理解它。當然如果有需要,盡管問我。

Farhana:在那些設計原則之上我聽說過很多設計模式。

Shubho:對的。設計模式只是對一些經常出現的場景的一些通用設計建議。這些靈感主要來自于面向對象原則。你可以把設計模式看作"框架",把OOD原則看作"規范".

Farhana:那么接下去我將學習設計模式嗎?

Shubho:是的,親愛的。

Farhana:那會很有意思,對嗎?

Shubho:是,那確實令人興奮。

轉載于:https://www.cnblogs.com/xyqCreator/archive/2012/10/23/2735234.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/379197.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/379197.shtml
英文地址,請注明出處:http://en.pswp.cn/news/379197.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

不安全代碼和指針資料匯編

不安全代碼和指針&#xff08;C# 編程指南&#xff09;為了保持類型安全&#xff0c;默認情況下&#xff0c;C# 不支持指針運算。不過&#xff0c;通過使用 unsafe 關鍵字&#xff0c;可以定義可使用指針的不安全上下文。有關指針的更多信息&#xff0c;請參見主題指針類型。 注…

ffmpeg-從flv文件中提取AAC音頻數據保存為文件

AAC ADTS格式協議&#xff1a; 從flv文件中提取AAC音頻數據保存為文件。 如果需要詳細了解AAC ADTS格式&#xff0c;可以查詢文檔。 原文件&#xff1a; 提取aac文件&#xff1a; main.c #include <stdio.h> #include <libavutil/log.h>> #include <lib…

Python-統計《水調歌頭·明月幾時有》字符出現次數。

統計《水調歌頭明月幾時有》字符出現次數。 明月幾時有&#xff0c;把酒問青天。 不知天上宮闕&#xff0c;今夕是何年&#xff1f; 我欲乘風歸去&#xff0c;又恐瓊樓玉宇&#xff0c;高處不勝寒。 起舞弄清影&#xff0c;何似在人間&#xff01; 轉朱閣&#xff0c;低綺戶&am…

Linux網絡編程入門 (轉載)

(一)Linux網絡編程--網絡知識介紹 Linux網絡編程--網絡知識介紹客戶端和服務端 網絡程序和普通的程序有一個最大的區別是網絡程序是由兩個部分組成的--客戶端和服務器端. 客戶端 在網絡程序中&#xff0c;如果一個程序主動和外面的程序通信&#xff0c;那么我們…

在Python中將字符串拆分為字符數組

Given a string and we have to split into array of characters in Python. 給定一個字符串&#xff0c;我們必須在Python中拆分為字符數組。 將字符串拆分為字符 (Splitting string to characters) 1) Split string using for loop 1)使用for循環分割字符串 Use for loop t…

SQL表值函數和標量值函數的區別 [轉]

SQL表值函數和標量值函數的區別 寫sql存儲過程經常需要調用一些函數來使處理過程更加合理&#xff0c;也可以使函數復用性更強&#xff0c;不過在寫sql函數的時候可能會發現&#xff0c;有些函數是在表值函數下寫的有些是在標量值下寫的&#xff0c;區別是表值函數只能返回一個…

N Queen(代碼、分析、匯編)

目錄&#xff1a;代碼&#xff1a;分析&#xff1a;匯編&#xff1a;代碼&#xff1a; main.c #include <stdio.h>/* 程序描述&#xff1a;輸出N*N中符合左右對角線與上下左右方向都沒被使用的位置在每一行的所有情況使用檢測左上角&#xff0c;正上角&#xff0c;右上…

kotlin 計算平方_Kotlin程序計算自然數之和

kotlin 計算平方Given a number number, and we have to calculate the sum of all natural numbers from 1 to number. 鑒于一些數字 &#xff0c;我們必須從1計算所有自然數的總和數量 。 Example: 例&#xff1a; Input:number 15Output:120用于計算Kotlin中自然數之和的…

Python-身份證核對

中華人民共和國居民身份證號碼由17 位數字和1位校驗碼組成。其中&#xff0c;前6位為所在地編號&#xff0c;第7~14 位為出生年月日&#xff0c;第15~17位為登記流水號&#xff0c;其中第17位偶數為女性&#xff0c;奇數為男性。校驗碼的生成規則如下: 將前面的身份證號碼17位數…

VC 加載套接字庫

//加載套接字庫 WORD wVersionRequested;//套接字庫版本信息 WSADATA wsaData; int err; wVersionRequested MAKEWORD(1,1); err WSAStartup(wVersionRequested,&wsaData); if(err ! 0){ //加載失敗 return; } if(LOBYTE(wsaData.wVersion) ! 1 || //判斷是不是所請求的…

統計各種字符個數

#include <stdio.h> #include <conio.h>int main(int argc, char * argv[]) {char ch;int letters 0, space 0, digit 0, others 0;printf("請輸入一組字符串:\n");while((chgetchar())!\n){if(ch>a && ch < z || ch >A &&…

樹存儲結構(代碼、分析、匯編)

目錄&#xff1a;代碼&#xff1a;分析&#xff1a;匯編&#xff1a;代碼&#xff1a; LinkList.h LinkList.c 線性表 GTree.h #ifndef _GTREE_H_ #define _GTREE_H_typedef void GTree;//定義樹類型 typedef void GTreeData;//定義節點中存放數據的類型 typedef void (GTre…

Python-《twinkle twinkle little star》統計單詞出現次數

統計英文兒歌《twinkle twinkle little star》中&#xff0c;使用到的單詞及其出現次數。要求去除單詞大小寫的影響&#xff0c;不統計標點符號的個數&#xff0c;并按降序輸出。 Twinkle, twinkle, little star, How I wonder what you are! Up above the world so high, Like…

二元矩陣峰值搜索_好斗的牛(二元搜索)

二元矩陣峰值搜索A farmer has built a long barn with N stalls. The stalls are placed in a straight manner at positions from x1, x2, ...xN. But his cows (C) are aggressive and don’t want to be near other cows. To prevent cows from hurting each other, he wan…

WinForm Paenl里面添加Form

Form7 f7 new Form7();f7.TopLevel false;f7.Parent this.panel1;this.panel1.Controls.Add(f7);f7.Show();轉載于:https://www.cnblogs.com/Haibocai/archive/2012/10/30/2746003.html

跳躍表SkipList

跳躍表(Skip List)是一種隨機化數據結構&#xff0c;基于并聯的鏈表&#xff0c;其效率可比擬于二叉查找樹(對于大多數操作需要O(log n)平均時間)。 基本上&#xff0c;跳躍列表是對有序的鏈表增加上附加的前進鏈接&#xff0c;增加是以隨機化的方式進行的&#xff0c;所以在列…

Python---冒泡排序、選擇排序

冒泡排序 依次輸入n個數&#xff0c;進行冒泡排序 冒泡排序法&#xff0c;即兩個相鄰的進行比較&#xff0c;比較之后換位置 def bubbleSort(arr):n len(arr)for i in range(n):for j in range(0, n-i-1):if arr[j] > arr[j1] :arr[j], arr[j1] arr[j1], arr[j]arr[] n…

react js 添加樣式_如何在React JS Application中添加圖像?

react js 添加樣式Hello! In this article, we will learn how to add images in React JS? I remember when I just started coding in React JS, I thought adding images would be done exactly as it is in HTML. I later realized that it was different. 你好&#xff0…

二叉樹(多路平衡搜索樹)-(代碼、分析、匯編)

目錄&#xff1a;代碼&#xff1a;分析&#xff1a;匯編&#xff1a;代碼&#xff1a; BTree.h #ifndef _BTREE_H_ #define _BTREE_H_#define BT_LEFT 0 //定義左子節點標識 #define BT_RIGHT 1 //定義右子節點標識typedef void BTree;//定義樹類型 typedef unsigned long lo…

window service服務安裝錯誤

今天按照園子里面的文章&#xff0c;弄了一個系統服務&#xff0c;可是一直裝不上去&#xff0c; 正在運行事務處理安裝。 正在開始安裝的“安裝”階段。查看日志文件的內容以獲得 D:\TecCreateSvc\TecJsCreateService.exe 程序集的進度。該文件位于 D:\TecCreateSvc\TecJsCre…