2017-09-14 195 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离子发生在电影名称和最近的电影被选中。