Java: для цикла и если алгоритм - PullRequest
4 голосов
/ 23 сентября 2010

У меня есть этот вопрос из задания по созданию Магазина, который сдает книги в аренду, используя Store.java и Book.java. Я закончил это задание, но мне любопытно, как лучше использовать алгоритм для конкретной части.

-

Book.java

public class Book {

    private String name;

    Book(String name)
        this.name = name;

    public String getName()
        return name;

}

Store.java

Внутри основной ();

 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();

Предположим, вход = Дьявол.

Теперь мне нужно выполнить простой поиск, чтобы проверить, существует ли конкретная книга.

Пример: * * один тысяча двадцать-одна

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

По-видимому, это цикл for, который циклически просматривает массив объектов и проверяет, существует ли такая Book. Теперь проблема возникает, когда я хочу дать вывод, что Книга не была найдена.

* +1025 * Пример:
 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 () или использовать другие методы?

Ответы [ 6 ]

6 голосов
/ 23 сентября 2010

Вы должны перебрать массив и использовать индекс / логический флаг для хранения информации о том, найдена книга или нет. Затем напечатайте сообщение в конце, основываясь на значении индекса / флага.

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().

Как я должен думать об этом объектно-ориентированным способом?

Если рассматривать один метод, то между процедурным и ОО-стилем нет большой разницы. Различия начинают проявляться на более высоком уровне, когда вы пытаетесь организовать кучу концептуально связанных данных и методов, которые работают с ними.

Парадигма ОО состоит в том, чтобы связать методы с данными, с которыми они работают, и инкапсулировать как в согласованные объекты, так и в классы. Эти классы предпочтительно являются представлениями важных концепций предметной области. Поэтому для вашего книжного магазина вы можете поместить весь код, связанный с книгами, в свой класс Book. Однако описанный выше метод поиска (и набор книг, с которыми он работает) не связан с каким-либо конкретным экземпляром книги, поэтому у вас есть другой выбор:

  • поместите и коллекцию книг, и метод поиска в Store (вероятно, в качестве обычных членов) или
  • поместите их в Book как static членов.

Первый выбор более естественный, поэтому я бы предпочел это. Однако при определенных обстоятельствах второй вариант может быть предпочтительным. В (ОО) дизайне едва ли когда-либо есть чистые ответы «да / нет» - скорее, компромиссы между различными вариантами, каждый из которых имеет свои сильные и слабые стороны.

2 голосов
/ 23 сентября 2010

Вы можете ввести состояние и вспомнить, нашли ли вы книгу или нет.

Если вы не используете Java 1.4 или более раннюю версию, вы также можете использовать синтаксис цикла foreach:

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

Кроме того, я бы посоветовал заглянуть в библиотеку Collections и заменить ваш массив списком или набором:

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

И, хотя это было возможно, вы могли бы подуматьо том, когда две книги равны и переопределить equals () и hashCode () соответственно.Если равный () будет изменен для проверки заголовка, вы можете просто использовать books.contains(new Book(input));, и библиотеки сделают всю работу за вас.

1 голос
/ 23 сентября 2010

Чтобы решить проблему лучше, вы должны понимать, что сила Java исходит не от самого языка, а от Java Framework.

Вы должны изучить использование Java Collection классы (больше никогда не работайте с массивами).Тогда вы сможете решить поиск с помощью только одной строки кода:

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

Чтобы сделать это, вы также должны научиться правильно реализовывать метод equals () вашего класса Book.

Счастливого обучения!

0 голосов
/ 15 февраля 2013

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 голосов
/ 23 сентября 2010

Вы уже получили довольно хороший совет. Вы спросили, существует ли более объектно-ориентированный подход к проблеме, поэтому я подумал, что попытаюсь пролить свет на нее. Как уже упоминал Питер на этом уровне разработки, это реализация одного метода, поэтому подход будет довольно похож, как, например, процедурный подход. В чем преимущество? Одним словом повторное использование. Если вам нужно было найти книгу по названию во многих местах, то перемещение кода в ее собственный класс поможет.

Итак, у вас есть один экземпляр 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;
   }
}

Итак, пара вещей, о которых нужно помнить. Во-первых, когда мы работаем с библиотекой, мы не знаем, есть ли там массив. Мы могли бы использовать массив, набор, список или базу данных (чаще всего). Дело в том, что код, вызывающий эти функции, работает только с интерфейсом библиотеки (не буквальным интерфейсом Java, а сигнатурой метода библиотеки). Также это интерфейс более высокого уровня. Нам не нужно перебирать книги, выполнять циклы, операторы if и т. Д. Мы просто вызываем метод, говорящий «Привет, найдите этот заголовок книги в библиотеке». Как это сделано, нам все равно. Это основной клиент Object Orientation, называемый инкапсуляцией, и он обманчиво силен. На самом деле речь идет о том, как мы делегируем ответственность в нашей программе и даем детали работы отдельным классам или классам. Если бы в Библиотеке были только открытые члены (например, books и bookCount) или getter / setters, то у клиента не было бы никаких преимуществ, потому что клиент все равно должен был бы выполнять всю тяжелую работу. Уловка ОО состоит в том, чтобы выяснить, что можно делегировать из объекта, не создавая проблем. Это требует практики и опыта.

Во-вторых, мы отделили презентацию от акта поиска книги. Метод, который вы написали, предполагал следующий шаг, который должен был напечатать «Эй, мы нашли это». Тем не менее, объект Library просто возвращает книгу вам, когда он ее находит, или NULL, если этого не произошло. Это позволяет печатать на консоль, отображать в графическом интерфейсе или сериализовать его в поток JSON на сервере. Акт поиска книги отделен от визуализации. Это еще один важный аспект программирования в целом, но в некоторой степени связанный с ориентацией объекта и инкапсуляцией. Обычно это называется разделением интересов. Консольное приложение заботится о поддержке пользовательского интерфейса и печати консоли. В то время как библиотека просто управляет каталогизацией и управлением коллекцией книг. То, как эти детали выполняются, не имеет значения.

В конце концов, библиотека - это класс многократного использования. Мы можем использовать его в консольном приложении, на рабочем столе, в Интернете или на сервере промежуточного программного обеспечения. Что еще более важно, мы также можем повторно использовать вызовы findByTitle или addBooks из нескольких мест в рамках одной программы. Кроме того, помещая методы с данными, мы создаем барьер для использования этой функции. Вы не можете сделать это нигде в вашей программе. Вы должны иметь ссылку на библиотеку. Если у вас нет ссылки на экземпляр библиотеки, вам не следует его вызывать. Это может быть проблематично для новых разработчиков, потому что им не хватает опыта для правильной организации своих программ, чтобы они не сталкивались с этим (тогда они начинают создавать объекты-ценности, создавать статические элементы, одиночные символы и т. Д., И все превращается в большой шарик грязи). Это обоюдоострый меч.

Еще одна вещь, которую я хотел бы отметить, это сказать, что мы хотели смоделировать две библиотеки. У нас есть библиотека в центре и в центре города, и мы хотим, чтобы люди могли проверять книги из любой библиотеки. С ОО это действительно легко представить:

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

Теперь мы можем проверять книги одного или другого. И я не использовал статику (то есть глобальные переменные), поэтому повторное использование этой логики действительно легко. Это основы ОО, так что это действительно глубокие темы. Странно, как я могу так много писать на очень простые темы. В любом случае, я надеюсь, что это помогло вам понять вашу программу немного глубже и понять, как вы можете использовать ОО, чтобы помочь вам.

0 голосов
/ 23 сентября 2010

Вот рабочее решение:

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.

   }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...