2010-09-23 62 views
4

我從一個任務創建一個商店出租這本書的問題,使用Store.java和Book.java。我完成了這個任務,但我很好奇爲特定部分提供更好的算法。Java:For循環和如果算法

-

Book.java

public class Book { 

    private String name; 

    Book(String name) 
     this.name = name; 

    public String getName() 
     return name; 

} 

Store.java

在main();

Book bookObj[] = new Book[3]; //Create 3 Array of Object. 
bookObj[0] = new Book("Game Over"); 
bookObj[1] = new Book("Shrek"); 
bookObj[2] = new Book("Ghost"); 
Scanner console = new Scanner(System.in) 
input = console.nextLine(); 

假設,input = Devil。

現在,我需要做一個簡單的搜索來檢查特定的書是否存在。

實施例:

for(int i = 0; i < bookObj.length; i++) { 
    if(bookObj[i].getName().equals(input)) 
     System.out.println("Book Found!"); 
} 

顯然,這是一個for循環,通過對象和檢查陣列週期是否這樣預訂存在。現在,當我想給出一個沒有找到該書的輸出時,就會出現問題。

實施例:

for(int i = 0; i < bookObj.length; i++) { 
    if(bookObj[i].getName().equals(input)) 
     System.out.println("Book Found!"); 
    else 
     System.out.println("Book not Found!"); 
} 

與上面的代碼的問題是,不預訂實測值將被打印三次。我的目標是避免這樣的問題。我確實有解決方案,但我仍然在尋找一個更好的使用getName()的方法,這在我看來仍然有改進的空間。

通常情況下,在結構化編程,我會做以下,

for(int i = 0; i < bookObj.length; i++) { 
    if(bookObj[i].getName().equals(input)) 
     System.out.println("Book Found!"); 
    else if(i == bookObj.length - 1) 
     System.out.println("Book not Found!"); 
} 

這有助於弄清楚究竟是一個循環的結束,並在搜索結束,但沒有成功的結果從搜索。

我應該如何以面向對象的方式來思考它?

所有的一切,我的問題是,

  1. 有沒有更好的方式來寫上面的代碼,而不是檢查,它是該行的結束?
  2. 有沒有更好的方法來利用getName()方法或使用其他方法?
+3

首先這個問題:你允許使用[Collections框架](http://download.oracle.com/javase/tutorial/collections/index.html)而不是數組嗎?有很大的改進空間,但是功課通常只限於你實際學到的東西。而且,因爲這還不清楚...... – BalusC 2010-09-23 14:40:24

+0

謝謝你的提示,但不幸的是,我被綁定到使用一個對象的數組這個任務。 – 2010-09-23 14:55:03

回答

6

您應該遍歷數組並使用索引/布爾型標誌來存儲是否找到該書。然後根據索引/標誌值在最後打印消息。

int foundAtIndex = -1; 
for(int i = 0; i < bookObj.length; i++) { 
    if(bookObj[i].getName().equals(input)) { 
     foundAtIndex = i; // store the actual index for later use 
     break;    // no need to search further 
    } 
} 
if(foundAtIndex >= 0) 
    System.out.println("Book Found!"); 
else 
    System.out.println("Book not Found!"); 

或者(除非你的任務明確要求使用數組),你應該更喜歡Set,它可以做搜索你到contains()一個電話。

我該如何以面向對象的方式來思考它?

在查看單個方法時,程序和OO風格之間沒有太大區別。當試圖組織大量概念上相關的數據和方法來處理這些差異時,差異開始出現在更高的層次上。

OO範例是將方法與它們操作的數據綁定在一起,並將它們封裝在相關的對象和類中。這些類最好是重要領域概念的表示。因此,對於您的書店,您可能希望將所有與圖書相關的代碼放入Book課程中。然而,上述搜索方法(和它運行在藏書)不涉及任何特定的書實例,讓你有不同的選擇:

  • 把兩者的藏書和搜索方法爲Store(大概是普通會員)或
  • 將它們放入Book作爲static成員。

第一個選擇更自然,所以我通常會更喜歡這個。但是,在特定情況下,第二種選擇可能更可取。在(OO)設計中,幾乎沒有乾淨的「是/否」答案 - 而是在不同選項之間進行權衡,每個選項都有自己的優勢和弱點。

+0

這是正確的。使用集合(如'Set')而不是數組。 – 2010-09-23 14:42:21

+0

+1,尤其是提到Set – Randolpho 2010-09-23 14:46:43

+1

讓我感到悲傷的是,數組被教導爲主數據結構。它們現在變成了特殊情況的數據結構。 – 2010-09-23 15:45:28

2

您可以引入狀態並記住您是否找到該書。

如果你不使用Java 1.4或更早版本,你也可以使用foreach循環語法:

boolean bookFound = false; 
for(Book currentBook : bookObj) { 
    if(currentBook.getName().equals(input)) 
    //TODO: see above 
} 

另外,我建議尋找到Collections library,並用列表或設置更換您的陣列:

Set<Book> books = new HashSet<Book>(); 
books.put(new Book("Game Over")); 
books.put(new Book("Shrek")); 
books.put(new Book("Ghost")); 

而且,雖然在它,你也可以考慮兩本書是否相等,並相應地重寫equals()和hashCode()。如果equal()會更改爲檢查標題,則可以簡單地使用books.contains(new Book(input));並讓庫爲您完成工作。

+0

請注意,當你找到你的物品時(或者使用break;或者在for循環中測試bookFound),你應該從循環中斷開。還要注意,在當前的java中增強的循環是一個更好的解決方案。 – KevinDTimm 2010-09-23 14:48:52

+0

包含()沒有出現在原始規範中 - equals()但是 - downvote否定 – KevinDTimm 2010-09-23 14:50:47

+0

@KevinDTimm我仍然編輯我的答案以包含contains()建議,因爲它可能有用。 – 2010-09-23 14:53:25

1

要更好地解決問題,您必須瞭解Java的強大功能不是來自語言本身,而是來自Java Framework。

您應該瞭解Java Collection類的用法(不再適用於數組)。然後,你就可以用代碼只是一條線,解決了搜索:

ArrayList<Book> listOfBooks; 
// init your list here 
listOfBooks.contains(new Book(input)); 

爲了使這項工作,你還必須學會如何正確地實現了equals()Book類的方法。

快樂學習!

0

這裏是一個工作的解決方案:

import java.util.Scanner; 

public class Store { 

    private static class Book { 

     private String name; 

     Book(String name) { 
     this.name = name; 
     } 

     public String getName() { 
     return name; 
     } 

    } 

    public static void main(String[] args) { 

     String input; 

     Book[] bookObj = new Book[3]; 

     bookObj[0] = new Book("Game Over"); 
     bookObj[1] = new Book("Shrek"); 
     bookObj[2] = new Book("Ghost"); 

     Scanner console = new Scanner(System.in); 
     input = console.nextLine(); 

     boolean found = false; 
     int i = 0; 
     while(!found && i < bookObj.length) { 

     if(bookObj[i].getName().equals(input)) { 

      System.out.println("Book Found at position : " + i); 
      found = true; 

     } else { 
      i++; 
     } 
     } 

     if(!found) { 
     System.out.println("Book not Found!"); 
     } 

     // Here i contains the indice of the element found in the array. 

    } 

} 
0

迄今爲止您得到了一些非常好的建議。你問是否有更多的面向對象的方式來思考這個問題,所以我想我會試着去闡明它。正如Peter在設計的這個級別中已經提到的那樣,這是一種單一的方法實現,所以這種方法將與程序方法相當類似。有什麼優勢?用一個詞重用。如果你需要在很多地方按名字找到一本書,那麼將代碼移到它自己的類中將會有所幫助。

因此,您擁有的是一個Book實例,以封裝單個圖書的行爲,但您希望擁有關於多本圖書或書籍集合的行爲。您可以保存數據(書本數組),並按照您在程序中列出的方法將它們分開的方法分開。但是,如果我們想收集一個地方在一堆書上做行爲,我們可以定義一個新的類。讓我們把它叫做圖書館,我們可以做一些這樣的:

public class Library { 
    private Book[] books; 
    private bookCount = 0; 

    public Library(int numberOfTotalBooks) { 
     books = new Book[numberOfTotalBooks]; 
    } 

    public boolean addBook(Book book) { 
     if(bookCount < book.length) { 
     books[bookCount++] = book; 
     return true; 
     } 
     return false; 
    } 

    public Book findByTitle(String title) { 
     for(int i = 0; i < bookCount; i++) { 
      if(books[i].getTitle().equals(title)) { 
      return books[i]; 
      } 
     } 
     // didn't find one 
     return null; 
    } 
} 

那麼幾件事情需要注意做事這種方式。一個是,當我們與一個圖書館合作時,我們不知道那裏有一個數組。我們可以使用一個數組,一個Set,一個List或一個數據庫(最常見)。調用這些函數的代碼只是與庫的接口(不是文字Java接口,而是庫的方法簽名)一起工作。這也是一個更高層次的界面。我們不用擔心迭代書籍,做循環,if語句等。我們只是調用一種方法,說「嘿,在圖書館找到這本書的名字」。如何做到這一點我們不在乎。這是面向對象的基本租戶,稱爲封裝,它看似強大。這是關於我們如何將責任委託給我們的計劃,並將工作細節提供給個人班級。如果圖書館只有公共成員(即書籍和bookCount),或者吸收/設置者,那麼客戶端將不會獲得任何優勢,因爲客戶端仍然需要完成所有繁重的工作。面向對象的訣竅是弄清楚可以委託給對象的內容,而不會產生問題。這需要練習和經驗。

這裏的第二件事是我們將演示文稿和尋找書的行爲分開了。你寫的方法假定下一步是打印「嘿,我們找到了。」但是,Library對象只是在找到它時返回Book,否則返回null。這樣就可以打印到控制檯,在GUI中顯示或者將其序列化爲服務器中的JSON流。找到一本書的行爲與可視化是分開的。這是編程的另一個重要方面,但一些與面向對象和封裝有關。這通常稱爲關注點分離。控制檯應用程序擔心支持UI和打印控制檯。圖書館只管理編目和管理圖書集。這些細節如何執行都不在乎。

最後庫是一個可重用的類。我們可以在控制檯應用程序,桌面,Web或中間件服務器中使用它。更重要的是,我們也可以在單個程序中重複使用來自多個位置的findByTitle或addBooks的調用。同樣,通過將數據與方法相結合,我們創造了一個障礙,可以使用該功能。你不能在你的程序中的任何地方做它。你必須有一個對圖書館的參考。如果你沒有引用一個庫實例,那麼你不應該調用它。這對於新開發人員來說可能會很麻煩,因爲他們缺乏經驗來正確組織他們的程序以避免陷入困境(然後他們開始做價值對象,創建靜態,單身等等,事情變成一大塊泥潭)。這是一把雙刃劍。

我還想指出的另一件事是說我們想模擬兩個庫。我們有一個圖書館在市中心和市中心,我們希望允許人們從圖書館借閱書籍。使用面向對象的代碼很容易:

Library uptown = new Library(50); 
Library downtown = new Library(100); 

現在我們可以檢查出其中的一本書。而且我沒有使用靜態(即全局變量),因此重複使用該邏輯非常簡單。這些是面向對象的基礎知識,所以它們是非常深刻的主題。奇怪的是,我可以在非常簡單的主題上寫很多東西。無論如何,我希望這有助於你更深入地理解你的程序,並看看如何使用面向對象來幫助你。

+0

謝謝,這是一個很好的提示,爲我的未來編程! – 2010-09-25 12:18:16

-1

chubbsondubs最接近給予正確回答這個問題

他所錯過的是,他的算法不正確,因爲它包含了兩個測試,當只需要一個人來。正確的代碼只需要3條語句,如下所示:

public boolean zLibaryContains(String title) { 
     books[bookCount] = title; 
     int xBook = 0; 
     while(true) 
      if(books[xBook].getTitle().equals(title)) 
       return xBook != bookCount; 
      else xBook++;    
    } 

明顯小於所有其他解決方案並且速度更快。簡化,簡化,簡化。

面向對象的代碼是支持糟糕設計的柺杖,否則這些設計太複雜而難以理解。我們的目標是編寫代碼,它很容易理解並保持OO是不必要的,並且會使程序變得更糟。當你的程序可以通過添加面向對象來改進時,這意味着你開始時做錯了什麼。

+0

-1用於發佈可能在第一行中拋出一個'ArrayIndexOutOfBoundsException'的代碼,同時將其他解決方案抨擊爲「不正確」。更不用說忽略Java編碼慣例。 – 2014-10-21 07:13:54

+0

@PéterTörök我的代碼中使用的技術是最有效的方法。第一行初始化一個標記(閱讀Knuth 1.4.4)。對於使用標誌變量並且甚至不知道標記是如何批評我的代碼的「程序員」有點滑稽。 – 2014-10-21 21:19:27

+0

您一再對其他人可能或不可能知道的關於編程的知識(基於最少的信息)進行徹底的指控。放心,我讀Knuth,並知道什麼是哨兵。然而,用一種語言工作的東西可能不會自動移植到另一種語言。正確性勝過效率。事實上,索引一個超過其分配大小的Java數組會導致一個'ArrayIndexOutOfBoundsException'。 (除非你事先保留一個額外的元素 - 這可能並不總是可能的,而且在你的答案的任何地方都沒有提及。) – 2014-10-22 09:55:04