tft每日頭條

 > 生活

 > if編程實例

if編程實例

生活 更新时间:2025-04-02 12:01:38

為什麼我們學習編程的第一條指令應該是最後使用的。

if編程實例(如何永遠擺脫煩人的)1

沒有人再使用 GOTO 指令,而且很少有編程語言仍然支持它。

我們已經成熟并确認意大利面條代碼是不可維護且容易出錯的。 結構化編程幾年前就解決了這個問題。

多虧了 Edsger Dijkstra 令人難以置信的論文:Go To Statement Considered Harmful,我們擺脫了這句話。

下一個演變步驟将是删除大多數 If 語句

ifs/Cases 和 Switches 是僞裝成結構化流程的 GOTO。

我們的工具将是面向對象的編程原則。

if編程實例(如何永遠擺脫煩人的)2

問題

大多數 IF 句都與偶然的決定有關。 這種耦合會産生連鎖反應,使代碼更難維護。

If 語句違反了開放/封閉原則。 我們的設計将不那麼可擴展并且無法擴展。

更重要的是,Ifs 為更嚴重的問題敞開了大門,例如開關、案例、默認值、返回、繼續和中斷。

它們使我們的算法更暗,并迫使我們構建意外複雜的解決方案。

軟件開發人員無法解釋為什麼我們使用這個分支語句。 這是一種代碼氣味。

解決方案

在我們繼續删除 IF 語句之前,我們應該确定它是必要的還是偶然的 If。

基本 IF

讓我們看一個基本的 IF 語句

class Moviegoer { constructor(age) { this.age = age; } watchXRatedMovie() { if (this.age < 18) throw new Error("You are not allowed to watch this movie"); else this.watchMovie(); } watchMovie() { // .. } } let jane = new Moviegoer(12); jane.watchXRatedMovie(); // Throws exception since Jane is too young to watch the movie

我們應該決定是否删除這個 if 句子。

我們必須了解它是代表業務規則(必要)還是實現工件(意外)。

在上述情況下,我們将尊重我們的雙射。 所以我們不會替換 if。

現實世界中的人們使用 IF 用自然語言描述年齡限制

意外 IF

現在讓我們深入研究糟糕的 IF。

class Movie { constructor(rate) { this.rate = rate; } } class Moviegoer { constructor(age) { this.age = age; } watchMovie(movie) { if ((this.age < 18) && (movie.rate == 'Adults Only')) throw new Error("You are not allowed to watch this movie"); // watch movie } } let jane = new Moviegoer(12); let theExorcist = new Movie('Adults Only'); jane.watchMovie(theExorcist); // Jane cannot watch the exorcist since she is 12

電影分級 IF 與真實世界 If 無關,而是與意外(和耦合)實現有關。

我們的設計決定是用字符串對評級進行建模。

這是一個既不開放擴展也不封閉修改的經典解決方案。

讓我們看看新要求會發生什麼。

class Movie { constructor(rate) { this.rate = rate; } } class Moviegoer { constructor(age) { this.age = age; } watchMovie(movie) { //!!!!!!!!!!!!!!!!! IFS ARE POLLUTING HERE !!!!!!!!!!!!!!!!!!!!!!!!!! if ((this.age < 18) && (movie.rate == 'Adults Only')) throw new Error("You are not allowed to watch this movie"); else if ((this.age < 13) && (movie.rate == 'PG 13')) throw new Error("You are not allowed to watch this movie"); // !!!!!!!!!!!!!!!! IFS ARE POLLUTING HERE !!!!!!!!!!!!!!!!!!!!!!!!!!! // watch movie } } let theExorcist = new Movie('Adults Only'); let gremlins = new Movie('PG 13'); let jane = new Moviegoer(12); jane.watchMovie(theExorcist); // Jane cannot watch the exorcist since she is 12 jane.watchMovie(gremlins); // Jane cannot watch gremlins since she is 12 let joe = new Moviegoer(16); joe.watchMovie(theExorcist); // Joe cannot watch the exorcist since he is 16 joe.watchMovie(gremlins); // Joe CAN watch gremlins since he is 16

我們可以檢測到一些代碼氣味:

  1. 代碼被 IF.
  2. 缺少默認語句。
  3. 新的評級将帶來新的IF。
  4. 代表評級的字符串不是一流的對象。 錯字将引入難以發現的錯誤。
  5. 我們被迫在 Movies 上添加 getter 來做出決定。

食譜

讓我們通過以下步驟解決這個問題:

1 - 為每個 IF 條件創建一個多态層次結構(如果它不存在)。

2 - 将每個 IF 主體移動到前一個抽象。

3 - 用多态方法調用替換 IF 調用。

在我們的示例中:

// 1. Create a Polymorphic Hierarchy for every IF condition // (if it doesn't already exist) class MovieRate { // If language permits this should be declared abstract } class PG13MovieRate extends MovieRate { //2. Move every *IF Body* to the former abstraction warnIfNotAllowed(age) { if (age < 13) throw new Error("You are not allowed to watch this movie"); } } class AdultsOnlyMovieRate extends MovieRate { //2. Move every *IF Body* to the former abstraction warnIfNotAllowed(age) { if (age < 18) throw new Error("You are not allowed to watch this movie"); } } class Movie { constructor(rate) { this.rate = rate; } } class Moviegoer { constructor(age) { this.age = age; } watchMovie(movie) { // 3. Replace IF Call by polymorphic method call movie.rate.warnIfNotAllowed(this.age); // watch movie } } let theExorcist = new Movie(new AdultsOnlyMovieRate()); let gremlins = new Movie(new PG13MovieRate()); let jane = new Moviegoer(12); // jane.watchMovie(theExorcist); // Jane cannot watch the exorcist since she is 12 // jane.watchMovie(gremlins); // Jane cannot watch gremlins since she is 12 let joe = new Moviegoer(16); // joe.watchMovie(theExorcist); // Joe cannot watch the exorcist since he is 16 joe.watchMovie(gremlins); // Joe CAN watch gremlins since he is 16

有了這個結果:

1- 代碼被 IF 污染

我們不應該再添加 IFS。 擴展模型就足夠了。

2-缺少默認語句

在這種情況下,不需要默認行為,因為異常會中斷流程。 在很多時候,一個 Null 對象就足夠了。

3-新的評級将帶來新的IF

我們将通過多态新實例來解決它。

4- 代表評級的字符串不是一流的對象。 錯字将引入難以發現的錯誤。

這隐藏在 Ratings 實現中。

5- 我們被迫在電影上添加吸氣劑來做出決定。

打破這種協作鍊

movie.rate.warnIfNotAllowed(this.age);

class Movie { constructor(rate) { this._rate = rate; // Rate is now private } warnIfNotAllowed(age) { this._rate.warnIfNotAllowed(age); } } class Moviegoer { constructor(age) { this.age = age; } watchMovie(movie) { movie.warnIfNotAllowed(this.age); // watch movie } }

評級是私有的,所以我們不會破壞封裝。

因此,我們可以安全地避免 getter。

将配方應用于所有 IF 條件

現在我們有了秘密公式,我們可以更進一步,嘗試删除與年齡相關的基本 IF 條件。

class Age { } class AgeLessThan13 extends Age { assertCanWatchPG13Movie() { throw new Error("You are not allowed to watch this movie"); } assertCanWatchAdultMovie() { throw new Error("You are not allowed to watch this movie"); } } class AgeBetween13And18 extends Age { assertCanWatchPG13Movie() { // No Problem } assertCanWatchAdultMovie() { throw new Error("You are not allowed to watch this movie"); } } class MovieRate { // If language permits this should be declared abstract // abstract assertCanWatch(); } class PG13MovieRate extends MovieRate { //2. Move every *IF Body* to the former abstraction assertCanWatch(age) { age.assertCanWatchPG13Movie() } } class AdultsOnlyMovieRate extends MovieRate { //2. Move every *IF Body* to the former abstraction assertCanWatch(age) { age.assertCanWatchAdultMovie() } } class Movie { constructor(rate) { this._rate = rate; // Rate is now private } watchByMe(moviegoer) { this._rate.assertCanWatch(moviegoer.age); } } class Moviegoer { constructor(age) { this.age = age; } watchMovie(movie) { movie.watchByMe(this); } } let theExorcist = new Movie(new AdultsOnlyMovieRate()); let gremlins = new Movie(new PG13MovieRate()); let jane = new Moviegoer(new AgeLessThan13()); // jane.watchMovie(theExorcist); // Jane cannot watch the exorcist since she is 12 // jane.watchMovie(gremlins); // Jane cannot watch gremlins since she is 12 let joe = new Moviegoer(new AgeBetween13And18()); // joe.watchMovie(theExorcist); // Joe cannot watch the exorcist since he is 16 joe.watchMovie(gremlins); // Joe CAN watch gremlins since he is 16

我們更換了所有的 IF。 在後一種情況下使用雙重調度技術

我們使用了我們的公式,它奏效了。 但有一種過度設計的味道。

  1. 代表年齡的類與我們模型上的真實概念無關。
  2. 模型太複雜。
  3. 我們将需要與新年齡段相關的新課程。
  4. 年齡組可能不相交。

我們應該避免最後的設計,并在必要條件和偶然條件之間設置明确的界限。

一個好的設計規則是,如果它們屬于同一領域(電影和收視率),則創建抽象,如果它們跨領域(電影和年齡),則不要這樣做。

Ifs很臭嗎?

根據上面顯示的證據。 我們應該将許多 IF 視為代碼異味,并用我們的方法解決它們。

為什麼會這樣?

本文(和許多其他文章)建議避免使用大多數 IF 句。 對于所有對其使用非常滿意的開發人員來說,這将是非常困難的。

請記住,懶惰和隐藏的假設非常植根于我們的職業。 幾十年來,我們一直(ab)使用 IF,我們的軟件并不是它的最佳版本。

結論

使用這種簡單的技術,我們将能夠以程序的方式删除所有意外的 if。

這将使我們的模型更少耦合,更廣泛。

關注七爪網,獲取更多APP/小程序/網站源碼資源!

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2025 - www.tftnews.com All Rights Reserved