2017-09-14 93 views
1
//Represents list books command for biblioteca 

public class ListBooksCommand implements Command { 

    private static final String BOOKS = "Books::"; 
    private static final String FORMAT = "%-35s %-35s %-35s"; 
    private static final String HEADER = String.format(FORMAT, "Name", "Author", "YearPublished"); 
    private static final String NO_BOOKS_AVAILABLE = "No Books Available"; 

    private final Biblioteca biblioteca; 
    private final IO io; 

    public ListBooksCommand(Biblioteca biblioteca, IO io) { 
     this.biblioteca = biblioteca; 
     this.io = io; 
    } 

    @Override 
    public void execute() { 
     if (this.biblioteca.isEmpty(Book.class)) { 
      this.io.println(NO_BOOKS_AVAILABLE); 
      return; 
     } 
     this.displayBooks(); 
    } 

    private void displayBooks() { 
     this.io.println(BOOKS); 
     this.io.println(HEADER); 
     this.io.println(this.biblioteca.representationOfAllLibraryItems(Book.class)); 
    } 

}  

public class ListMoviesCommand implements Command { 

    private static final String Movies = "Movies::"; 
    private static final String FORMAT = "%-35s %-35s %-35s"; 
    private static final String HEADER = String.format(FORMAT, "Name", "Director", "YearPublished"); 
    private static final String NO_BOOKS_AVAILABLE = "No Movies Available"; 

    private final Biblioteca biblioteca; 
    private final IO io; 

    public ListBooksCommand(Biblioteca biblioteca, IO io) { 
     this.biblioteca = biblioteca; 
     this.io = io; 
    } 

    @Override 
    public void execute() { 
     if (this.biblioteca.isEmpty(Movie.class)) { 
      this.io.println(NO_MOVIES_AVAILABLE); 
      return; 
     } 
     this.displayMovies(); 
    } 

    private void displayMovies() { 
     this.io.println(MOVIES); 
     this.io.println(HEADER); 
     this.io.println(this.biblioteca.representationOfAllLibraryItems(MOVIE.class)); 
    } 

} 

我在這裏有兩個類,一個是listbooks命令,listmovies命令都在biblioteca上執行。 Book和Movie都是類型LibraryItem(接口)。 以下兩個代碼都是一樣的。兩者都會要求biblioteca獲得自己類型的代表性。這兩個命令都會顯示該表示。如何刪除重複?

這是藏書實現

//Represents a library 

public class Biblioteca { 

    private final List<LibraryItem> allLibraryItems; 

     public String representationOfAllLibraryItems(Class<? extends LibraryItem> itemType) { 
    return this.allLibraryItems 
      .stream() 
      .filter(libraryItem -> libraryItem.getClass().equals(itemType)) 
      .map(LibraryItem::representation) 
      .collect(Collectors.joining(LINE_SEPARATOR)); 
} 

public boolean isEmpty(Class<? extends LibraryItem> itemType) { 
    return this.allLibraryItems.stream().noneMatch(libraryItem -> libraryItem.getClass().equals(itemType)); 
} 

} 

請建議我的模式,以避免重複。

+0

這些類型的'執行命令'似乎是錯誤的。他們應該實現/擴展處理這種bookeping的父類型(例如'LibraryItem'抽象類 - 你已經提到這種類型已經存在)。如果存在任何這樣的項目,抽象類應該處理詢問「Biblioteca」,以便子類只關心它們如何顯示。 – dimo414

+0

你的問題有點不清楚。你說的是,下面的代碼都是類似的。你在說什麼代碼? –

+0

這兩個listbooksCommand,ListMoviesCommand都有相同的代碼。 – Srinivas

回答

0

您可以創建一個通用類ListItemsCommand,它將接受項目名稱或類作爲列表和檢查空列表的參數。 然後調用ListItemsCommand與項目類型一樣MovieBook

1

注:我不知道您的要求。我只是在這個答案中提出一些一般設計觀察。

觀察1:Biblioteca是一個圖書館,庫項目。在你的情況下,庫中的物品是Movie物品和Book物品。所以圖書館兩個主要類型的項目(或它甚至可以包含更多,無所謂)。因此的Biblioteca的構件應該是:

private HashMap<Class<? extends LibraryItem>, List<LibraryItem>> libraryItems; 

具有項目類型作爲KeyList<LibraryItem>作爲值A的地圖。 Biblioteca還應該包含查詢方法,該方法將返回給定的項目類型的表示和所有項目類型的表示。所以,在我看來,Biblioteca類應該是這樣的:

public class Biblioteca { 
    private HashMap<Class<? extends LibraryItem>, List<LibraryItem>> libraryItems; 

    public Biblioteca(HashMap<Class<? extends LibraryItem>, List<LibraryItem>> libraryItems) { 
     this.libraryItems = libraryItems; 
    } 

    /* 
    * Representation of a given type 
    */ 
    public String representationOfLibraryItemType(Class<? extends LibraryItem> itemType) { 
     if(libraryItems.containsKey(itemType)) { 
      return libraryItems.get(itemType).stream() 
             .filter(libraryItem -> libraryItem.getClass().equals(itemType)) 
             .map(LibraryItem::representation) 
             .collect(Collectors.joining(System.lineSeparator())); 
     } else { 
      throw new IllegalArgumentException("Missing type " + itemType.getSimpleName()); 
     } 
    } 

    /* 
    * Representation of all types 
    */ 
    public List<String> representationOfAllLibraryItems() { 

     return libraryItems.values() 
          .stream() 
          .flatMap(list -> list.stream() 
               .map(LibraryItem::representation)) 
          .collect(Collectors.toList()); 
    } 
} 

的方法representationOfLibraryItemType應在Class項目類型採取過濾。如果在庫中找到該項目類型,則返回它的表示或者拋出異常,說明它是未知的項目類型。

另一方面,representationOfAllLibraryItems()不應該採取任何輸入參數。它應該返回庫中的所有可用表示。

觀察2:你的LibraryItem應該是一個抽象類,你的庫中的每個項目都應該擴展這個特定的類。因爲Movieis-aLibraryItem and Bookis-aLibraryItem。現在,您的每件商品都可以覆蓋representation()方法,這是抽象方法LibraryItem。你LibraryItem類應該是這個樣子:

public abstract class LibraryItem { 
    abstract String representation(); 
} 

觀察3:BookMovie類應該是獨立的Biblioteca,因爲他們只是在項目-A庫。今天,他們在名爲Biblioteca的圖書館中,明天他們可以在名爲CentralHallLibrary的圖書館中。所以,你的項目類應該看起來像這樣:

/* 
* Book Item 
*/ 
public class Book extends LibraryItem { 

    private String title; 
    private String author; 
    private String publishedYear; 


    public Book(String title, String author, String publishedYear) { 
     this.title = title; 
     this.author = author; 
     this.publishedYear = publishedYear; 
    } 

    @Override 
    public String representation() { 
     /* 
     * I'm just returning a call to toString 
     * from this method. You can replace it 
     * with your representation logic. 
     */ 
     return toString(); 

    } 

    @Override 
    public String toString() { 
     return "Book [title=" + title + ", author=" + author + ", publishedYear=" + publishedYear + "]"; 
    } 

} 

/* 
* Movie Item 
*/ 
public class Movie extends LibraryItem { 
    private String title; 
    private String director; 
    private String releaseYear; 


    public Movie(String title, String director, String releaseYear) { 
     this.title = title; 
     this.director = director; 
     this.releaseYear = releaseYear; 
    } 



    @Override 
    public String representation() { 
     /* 
     * I'm just returning a call to toString 
     * from this method. You can replace it 
     * with your representation logic. 
     */ 
     return toString(); 

    } 


    @Override 
    public String toString() { 
     return "Movie [title=" + title + ", director=" + director + ", releaseYear=" + releaseYear + "]"; 
    } 

} 

觀察4:我沒有找到任何使用Command類你正在使用的。因爲,正如我所看到的,您的Command類只有一個名爲​​的方法用於顯示錶示。通常我會在客戶端(UI)放置這樣的「顯示」代碼。如果Command班除了印刷材料之外沒有別的功能,在我看來沒有必要。

測試設計:讓我們創建幾個Book項目和幾個Movie項目,然後添加這些到Biblioteca庫現在

 Book effJava = new Book("Effective Java", "Josh Bloch", "2008"); 
     Book cloudNativeJava = new Book("Cloud Native Java", "Josh Long", "2017"); 
     Book java9modularity = new Book("Java 9 Modularity", "Paul Bakker", "2017"); 

     Movie gotgV2 = new Movie("Guardians of the Galaxy Vol. 2", "James Gunn", "2017"); 
     Movie wonderWoman = new Movie("Wonder Woman", "Patty Jenkins", "2017"); 
     Movie spiderHomeCmg = new Movie("Spider-man Homecoming", "Jon Watts", "2017"); 

     List<LibraryItem> bookItems = new ArrayList<>(); 
     List<LibraryItem> movieItems = new ArrayList<>(); 

     bookItems.add(java9modularity); 
     movieItems.add(spiderHomeCmg); 
     bookItems.add(cloudNativeJava); 
     movieItems.add(wonderWoman); 
     bookItems.add(effJava); 
     movieItems.add(gotgV2); 

     HashMap<Class<? extends LibraryItem>, List<LibraryItem>> store = new HashMap<>(); 
     store.put(Movie.class, movieItems); 
     store.put(Book.class, bookItems); 

     //CREATE STORE 
     Biblioteca bibloiteca = new Biblioteca(store); 

,在查詢庫中的所有作品 -

List<String> allLibraryItemsRep = bibloiteca.representationOfAllLibraryItems(); 

將返回既有Movie也有Book表示的結果。

上詢問具體的項目類型庫 -

String movieRep = bibloiteca.representationOfLibraryItemType(Movie.class); 
String bookRep = bibloiteca.representationOfLibraryItemType(Book.class); 

將返回特定的作品 -

Movie [title=Spider-man Homecoming, director=Jon Watts, releaseYear=2017] 
Movie [title=Wonder Woman, director=Patty Jenkins, releaseYear=2017] 
Movie [title=Guardians of the Galaxy Vol. 2, director=James Gunn, releaseYear=2017] 

Book [title=Java 9 Modularity, author=Paul Bakker, publishedYear=2017] 
Book [title=Cloud Native Java, author=Josh Long, publishedYear=2017] 
Book [title=Effective Java, author=Josh Bloch, publishedYear=2008] 

上詢問該類型庫中不存在庫 -

String carRep = bibloiteca.representationOfLibraryItemType(Car.class); 

會拋出異常 -

java.lang.IllegalArgumentException: Missing type Car 

我明白這是一個相當長的答案,並希望這會給設計帶來一些清晰。

0

如果你想刪除重複,我建議使用收集與groupingBy。這允許您指定哪個是用於重複數據刪除(或分組)的關鍵字,以及在重複的情況下選擇要從重複集合中選擇的元素的還原函數。

下面是一個簡單的方法與groupingBy收藏家:

public String representationOfAllLibraryItems(Class<? extends LibraryItem> itemType) { 
    return this.allLibraryItems 
      .stream() 
      .filter(libraryItem -> libraryItem.getClass().equals(itemType)) 
      .collect(Collectors.groupingBy(LibraryItem::getName, LinkedHashMap::new, 
        Collectors.reducing((o1, o2) -> o1.toString().compareTo(o2.toString()) < 0 ? o1 : o2))) 
      .values() 
      .stream() 
      .map(Optional::get) 
      .map(LibraryItem::representation) 
      .collect(Collectors.joining(LINE_SEPARATOR)); 
} 

這裏是一個小的測試中,我們通過電影的名字去複製,然後在數據中的最新條目:

public static void main(String[] args) { 
    List<LibraryItem> items = Arrays.asList(new Movie("Valerian", "Luc Besson", "2017"), 
      new Movie("Valerian", "Luc Besson", "2016"), 
      new Movie("Spiderman", "Sam Raimi", "2002"), 
      new Movie("Spiderman", "Sam Raimi", "2001"), 
      new Movie("Spiderman", "Sam Raimi", "2003")); 
    Biblioteca biblioteca = new Biblioteca(items); 
    System.out.println(biblioteca.representationOfAllLibraryItems(Movie.class)); 
} 

結果看起來是這樣的:

Luc Besson - Valerian - 2017 
Sam Raimi - Spiderman - 2003 

這裏去duplicat離子發生在電影名稱和最近的電影被選中。