//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获得自己类型的表示。两个命令都将显示表示。
这是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 :(得分:1)
注意:我不了解您的要求。我只是在这个答案中提出一些一般性的设计观察。
观察1: Biblioteca
是一个库,拥有库项目。在您的情况下,库中的项目是Movie
项和Book
项。因此,库具有两种主要类型的项目(或者甚至可以包含更多项目。无关紧要)。因此Biblioteca
的成员应该是:
private HashMap<Class<? extends LibraryItem>, List<LibraryItem>> libraryItems;
项目类型为Key
且List<LibraryItem>
为值的地图。
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
应该采用{{1>} 项类型进行过滤。如果在库中找到了项类型,则返回它的表示,否则抛出异常,说明它是未知的项类型。
另一方面,Class
不应该接受任何输入参数。它应该返回库中的所有可用表示。
观察2:您的representationOfAllLibraryItems()
应该是一个抽象类,库中的每个项都应该扩展此特定类。由于LibraryItem
是-a Movie
而LibraryItem
是-a Book
。现在,您的每个商品都可以覆盖LibraryItem
方法,这是representation()
中的抽象方法。您的LibraryItem
课程应该如下所示:
LibraryItem
观察3:您的public abstract class LibraryItem {
abstract String representation();
}
和Book
课程应独立于Movie
,因为它们只是 in-a 中的项目图书馆。今天他们在一个名为Biblioteca
的图书馆,明天他们可以在名为Biblioteca
的图书馆。所以,你的项目类应该是这样的:
CentralHallLibrary
观察4:我没有找到您正在使用的/*
* 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 + "]";
}
}
课程的任何用途。因为,正如我所见,您的Command
类只有一个名为Command
的方法用于显示表示。通常我会在客户端(UI)中放置这样的“显示”代码。如果execute()
类除了仅打印内容之外没有其他功能,我认为没有必要。
测试设计:让我们创建几个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);
我知道这是一个非常冗长的答案,并希望这能使设计更清晰。
答案 1 :(得分:0)
您可以创建一个通用类ListItemsCommand
,它将接受项目名称或类作为列出和检查空列表的参数。
然后使用ListItemsCommand
或Movie
Book
答案 2 :(得分: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
此处重复数据删除是通过电影名称进行的,并且选择了最近的电影。